xcoj 1103 插线板(树链刨分求最大子段和)
1103: 插线板
时间限制: 1 Sec 内存限制: 128 MB
提交: 14 解决: 7
题目描述
从前有一堆古老的插线板,任意两个插线板之间只有一根导线相连,最终形成一个树状结构。我们假设电线的电阻可以忽略。由于年代久远,插线板的状况不容乐观。每个插线板都对电流有一定的影响,用一个整数表示,若为正,表示对电流起到稳定作用,越大越稳定,若为负,代表对电流产生不好的影响。插线板在连接后。这种影响会叠加,比如a和b连接,a的影响为-1,b为3,则a到b的影响为2。现在提供操作1和2,操作1表示求出插线板a到插线板b之间对电流影响最为乐观的一段的影响数值。(注:数据有问题,这一段元素可以为空)即将a到b的这条“链”取出,形成一个关于影响的序列,这个序列的最大子段和。操作2表示将a到b的链上所有插线板对电流的影响改为一个数值(包括a和b)。现给出插线板的初始状况,请按照要求进行操作,输出结果。
输入
单组测试数据
第一行为插线板个数n。
第二行为插线板1到n初始状态对电流的影响数值。(数值绝对值不超过10000)
第三行开始有n-1行,每行两个数a和b,表示a、b有电线连接,保证形成一棵树。
之后一行有一个正整数m,代表操作个数。
最后m行,每行第一个数为1或2,代表操作种类,若为1,后面跟随两个数l和r,代表求出l和r之间的最好影响数值。若为2,后面跟随三个数l、r和c,代表修改l到r的插线板的影响为c。
输出
对每个操作1输出一个整数,代表最好影响数值,每个输出用一个空格隔开。
样例输入
-3 -2 1 2 3
1 2
2 3
1 4
4 5
3
1 2 5
2 3 4 2
1 2 5
样例输出
提示
n,m<=100000
来源
emm这题卡了我好久。。。
由于我校oj的数据贼弱。。暴力就可以过,甚至比我写的o(log(n)^2*n)还快。
暴力的做法就是对于题目所说的点求最近公共祖先(Tarjan+并查集,欧拉序列+st,求2^k的祖先然后不断向上找公共祖先),然后修改的时候把所有点逐个修改,求值的时候把所有点拿出来,求前缀和,维护最小值搞一下就好了。
学长的博客链接做法:http://www.cnblogs.com/neopenx/p/4503066.html ,暴力法。
#include "cstdio"
#include "cstring"
#include "vector"
#include "algorithm"
using namespace std;
#define maxn 100005
#define inf 0x3f3f3f3f
int head[maxn],qhead[maxn],lag[maxn],kth[maxn],tot1,tot2,f[maxn],vis[maxn],ancestor[maxn],p[maxn],s1[maxn],s2[maxn];
bool isUpdate[maxn];
struct Edge
{
int to,next;
}e[maxn*];
struct Query
{
int from,to,next,idx,c;
}q[maxn*];
void addedge(int u,int v)
{
e[tot1].to=v;
e[tot1].next=head[u];
head[u]=tot1++;
}
void addquery(int u,int v,int idx,int c=inf)
{
q[tot2].from=u;
q[tot2].to=v;
q[tot2].next=qhead[u];
q[tot2].idx=idx;
if(c!=inf) q[tot2].c=c;
qhead[u]=tot2++;
}
int find(int x) {return x!=f[x]?f[x]=find(f[x]):x;}
void Union(int u,int v)
{
u=find(u),v=find(v);
if(u!=v) f[v]=u;
}
void LCA(int u)
{
vis[u]=true;
f[u]=u;
for(int i=head[u];i!=-;i=e[i].next)
{
int v=e[i].to;
if(!vis[v])
{
p[v]=u;
LCA(v);
Union(u,v);
}
}
for(int i=qhead[u];i!=-;i=q[i].next)
{
int v=q[i].to;
if(vis[v]) ancestor[q[i].idx]=find(v);
//or storage e[i].lca=e[i^1].lca=find(v)
}
}
int sum(int num)
{
s2[]=s1[];
int Max=,Min=;
for(int i=; i<num; i++)
s2[i]=s2[i-]+s1[i];
for(int i=;i<num;i++)
{
Min=min(Min,s2[i]);
Max=max(Max,s2[i]-Min);
}
return Max;
}
int main()
{
//freopen("in.txt","r",stdin);
int T,n,m,u,v,c,cmd,qcnt=;
scanf("%d",&n);
tot1=tot2=;
memset(head,-,sizeof(head));
memset(qhead,-,sizeof(qhead));
memset(vis,,sizeof(vis));
memset(isUpdate,,sizeof(isUpdate));
for(int i=;i<=n;i++) scanf("%d",&lag[i]);
for(int i=; i<n-; i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
scanf("%d",&m);
for(int i=; i<m; i++)
{
scanf("%d",&cmd);
if(cmd==)
{
scanf("%d%d%d",&u,&v,&c);
addquery(u,v,i,c);
addquery(v,u,i,c);
isUpdate[i]=true;
}
else
{
scanf("%d%d",&u,&v);
addquery(u,v,i);
addquery(v,u,i);
}
}
LCA();
vector<int> ans;
for(int i=; i<tot2; i=i+)
{
int u=q[i].from,v=q[i].to,idx=q[i].idx;
int ed=ancestor[idx],cnt=;
if(isUpdate[qcnt])
{
int c=q[i].c;
while(u!=ed) lag[u]=c,u=p[u];
lag[ed]=c;
while(v!=ed) lag[v]=c,v=p[v];
}
else
{
while(u!=ed) s1[cnt++]=lag[u],u=p[u];
s1[cnt++]=lag[ed];
vector<int> rev;
while(v!=ed) rev.push_back(lag[v]),v=p[v];
for(int j=rev.size()-; j>=; j--) s1[cnt++]=rev[j];
int x=sum(cnt);
ans.push_back(x);
}
qcnt++;
}
for(int i=;i<ans.size()-;i++) printf("%d ",ans[i]);
printf("%d\n",ans[ans.size()-]);
}
然后我的做法是经典的线段树求区间最大子段和的做法,维护包含区间左端点的最大值lt,右端点的最大值rt,区间内最大值in,以及区间总和all。但是题目给的是一棵树,我们把它树链刨分以后再把一段一段地求前述四个值并合并。然后找到合并后的最大值即为答案。
#include<bits/stdc++.h>
#define clr(x) memset(x,0,sizeof(x))
#define clr_1(x) memset(x,-1,sizeof(x))
#define INF 0x3f3f3f3f
#define mod 1000000007
#define LL long long
using namespace std;
const int N=1e4+;
struct edg
{
int next,to;
}edge[N<<];
int head[N],etot;
void addedge(int u,int v)
{
edge[++etot]=(edg){head[u],v};
head[u]=etot;
return ;
}
int fro[N],bac[N],dep[N],fa[N],val[N],top[N],clk,tsize[N],son[N],dfn[N];
struct node
{
int l,r,tag,lt,rt,in,all;
}tree[N<<];
int n,m,k,u,v,c,op;
void init()
{
etot=;
clk=;
clr_1(head);
dep[]=;
fa[]=;
return ;
}
void dfs1(int u)
{
top[u]=u;
tsize[u]=;
son[u]=;
int p;
for(int i=head[u];i!=-;i=edge[i].next)
{
p=edge[i].to;
if(p!=fa[u])
{
fa[p]=u;
dep[p]=dep[u]+;
dfs1(p);
tsize[u]+=tsize[p];
if(!son[u] || tsize[p]>tsize[son[u]] )
son[u]=p;
}
}
return ;
}
void dfs2(int u)
{
fro[u]=++clk;
dfn[clk]=u;
int p;
if(son[u])
{
top[son[u]]=top[u];
dfs2(son[u]);
}
for(int i=head[u];i!=-;i=edge[i].next)
{
p=edge[i].to;
if(p!=fa[u] && p!=son[u])
dfs2(p);
}
bac[u]=clk;
return ;
}
void pushup(int i)
{
tree[i].all=tree[i<<].all+tree[i<<|].all;
tree[i].lt=max(max(tree[i<<].lt,tree[i<<].all+tree[i<<|].lt),tree[i].all);
tree[i].rt=max(max(tree[i<<|].rt,tree[i<<|].all+tree[i<<].rt),tree[i].all);
tree[i].in=max(max(tree[i<<].in,tree[i<<|].in),tree[i<<].rt+tree[i<<|].lt);
return ;
}
void pushdown(int i)
{
if(tree[i].tag!=INF)
{
if(tree[i].l!=tree[i].r)
{
tree[i<<].tag=tree[i].tag;
tree[i<<].all=(tree[i<<].r-tree[i<<].l+)*tree[i<<].tag;
tree[i<<].lt=tree[i<<].rt=tree[i<<].in=(tree[i<<].tag>=?tree[i<<].all:tree[i<<].tag);
tree[i<<|].tag=tree[i].tag;
tree[i<<|].all=(tree[i<<|].r-tree[i<<|].l+)*tree[i<<|].tag;
tree[i<<|].lt=tree[i<<|].rt=tree[i<<|].in=(tree[i<<|].tag>=?tree[i<<|].all:tree[i<<|].tag);
}
tree[i].tag=INF;
}
return ;
}
void init(int i,int l,int r)
{
tree[i]=(node){l,r,INF};
if(l==r)
{
tree[i].lt=tree[i].rt=tree[i].in=tree[i].all=val[dfn[l]];
return ;
}
int mid=(l+r)>>;
init(i<<,l,mid);
init(i<<|,mid+,r);
pushup(i);
return ;
}
void update(int i,int l,int r,int c)
{
if(tree[i].l>=l && tree[i].r<=r)
{
tree[i].all=(tree[i].r-tree[i].l+)*c;
tree[i].lt=tree[i].rt=tree[i].in=(c>=?tree[i].all:c);
tree[i].tag=c;
return ;
}
pushdown(i);
int mid=(tree[i].l+tree[i].r)>>;
if(l<=mid)
update(i<<,l,r,c);
if(r>mid)
update(i<<|,l,r,c);
pushup(i);
return ;
}
node query(int i,int l,int r)
{
if(tree[i].l>=l && tree[i].r<=r)
return tree[i];
pushdown(i);
int mid=(tree[i].l+tree[i].r)>>;
if(l>mid)
return query(i<<|,l,r);
else if(r<=mid)
return query(i<<,l,r);
else
{
node tmplt=query(i<<,l,r),tmprt=query(i<<|,l,r);
node tmp;
tmp.all=tmplt.all+tmprt.all;
tmp.lt=max(max(tmplt.lt,tmplt.all+tmprt.lt),tmp.all);
tmp.rt=max(max(tmprt.rt,tmprt.all+tmplt.rt),tmp.all);
tmp.in=max(max(tmplt.in,tmprt.in),tmplt.rt+tmprt.lt);
return tmp;
}
}
void tupdate(int u,int v,int c)
{
int tpu=top[u],tpv=top[v];
while(tpu!=tpv)
{
if(dep[tpu]<dep[tpv])
{
swap(u,v);
swap(tpu,tpv);
}
update(,fro[tpu],fro[u],c);
u=fa[tpu];
tpu=top[u];
}
if(dep[u]<dep[v])
swap(u,v);
update(,fro[v],fro[u],c);
return ;
}
int tquery(int u,int v)
{
int tpu=top[u],tpv=top[v];
node tmp[];
clr(tmp);
bool flag[]={,};
int now=;
node tmpn,tp;
int ans=;
while(tpu!=tpv)
{
if(dep[tpu]<dep[tpv])
{
swap(u,v);
swap(tpu,tpv);
now^=;
}
tmpn=query(,fro[tpu],fro[u]);
if(!flag[now])
{
tmp[now]=tmpn;
flag[now]=;
}
else
{
tp.all=tmp[now].all+tmpn.all;
tp.lt=max(max(tmpn.lt,tmpn.all+tmp[now].lt),tp.all);
tp.rt=max(max(tmp[now].rt,tmp[now].all+tmpn.rt),tp.all);
tp.in=max(max(tmp[now].in,tmpn.in),tmpn.rt+tmp[now].lt);
tmp[now]=tp;
}
u=fa[tpu];
tpu=top[u];
}
if(dep[u]<dep[v])
swap(u,v),now^=;
tmpn=query(,fro[v],fro[u]);
if(flag[now])
{
tp.all=tmp[now].all+tmpn.all;
tp.lt=max(max(tmpn.lt,tmpn.all+tmp[now].lt),tp.all);
tp.rt=max(max(tmp[now].rt,tmp[now].all+tmpn.rt),tp.all);
tp.in=max(max(tmp[now].in,tmpn.in),tmpn.rt+tmp[now].lt);
tmpn=tp;
}
if(flag[now^])
{
tp.in=max(max(tmp[now^].in,tmpn.in),tmpn.lt+tmp[now^].lt);
tmpn=tp;
}
return tmpn.in;
}
int main()
{
init();
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&val[i]);
for(int i=;i<=n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs1();
dfs2();
init(,,n);
scanf("%d",&m);
bool inf=;
for(int i=;i<=m;i++)
{
scanf("%d",&op);
if(op==)
{
scanf("%d%d",&u,&v);
if(!inf)
{
inf=;
printf("%d",max(tquery(u,v),));
}
else printf(" %d",max(tquery(u,v),));
}
else
{
scanf("%d%d%d",&u,&v,&c);
tupdate(u,v,c);
}
}
printf("\n");
return ;
}
所以。。暴力出奇迹?
xcoj 1103 插线板(树链刨分求最大子段和)的更多相关文章
- bzoj 5210(树链刨分下做个dp)
5210: 最大连通子块和 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 211 Solved: 65[Submit][Status][Discus ...
- hdu 5452(树链刨分)
看到题目,想了挺长时间,发现不会,然后看着样子像是树上成段操作,所以查了下树链刨分,结果真的就是这个东西... Minimum Cut Time Limit: 3000/2000 MS (Java/O ...
- 树链刨分(class版)
class版树链剖(刨)分 感谢沙华大佬的赞助 其实没什么太大变化,就是用了几次一顿乱指... CODE: #include<iostream> #include<cstdio> ...
- HDU - 3966 树链刨分
题目传送门 操作就是询问某个点的值, 然后就是对一条路径上的值全部修改. 最基本的树刨题目了. 树刨的思想: 1. 对于每个点找到他的重儿子. void dfs1(int o, int u){ sz[ ...
- POJ 2763 Housewife Wind 树链拋分
一.前言 这破题WA了一天,最后重构还是WA,最后通过POJ讨论版得到的数据显示,我看上去是把某个变量写错了..于是,还是低级错误背锅啊....代码能力有待进一步提升2333333 二.题意 某家庭主 ...
- HDU 3966 Aragorn's Story 树链拋分
一.写在前面 终于开始开坑link-cut-tree这个了,对于网上找到的大佬的前进路线,进行了一番研发,发现实际上可以实现对于树链拋分的制作.经历了若干长时间之后终于打了出来(为什么每次学什么东西都 ...
- P3565 由简单的树形dp 引入 长链刨分
这道题感觉不太行 因为自己没想出来. 先说一下暴力吧,取三个点 让两两之间的距离相等怎么做呢,看起来是很复杂的样子的,但是仔细观察发现 答案出自一个点的儿子之间 或者儿子和父亲之间. 暴力枚举三个点然 ...
- 树链剖分 (求LCA,第K祖先,轻重链剖分、长链剖分)
2020/4/30 15:55 树链剖分是一种十分实用的树的方法,用来处理LCA等祖先问题,以及对一棵树上的节点进行批量修改.权值和查询等有奇效. So, what is 树链剖分? 可以简单 ...
- hdu 3804树链剖分+离线操作
/* 树链刨分+离线操作 题意:给你一棵树,和询问x,y 从节点x--节点1的小于等于y的最大值. 解:先建一个空树,将树的边权值从小到大排序,将询问y按从小到大排序 对于每次询问y将小于等于y的边权 ...
随机推荐
- MySQL查询 45道练习题
SQL查询45道练习题 1.查询Student表中的所有记录的Sname.Ssex和Class列.select sname,ssex,class from student2.查询教师所有的单位即不重复 ...
- UIPikerView的属性---iOS-Apple苹果官方文档翻译
本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/C ...
- Spring4+SpringMVC+MyBatis整合思路(山东数漫江湖)
1.Spring框架的搭建 这个很简单,只需要web容器中注册org.springframework.web.context.ContextLoaderListener,并指定spring加载配置文件 ...
- js获取链接参数
var url = location.search; var Request = new Object(); if(url.indexOf("?")!=-1){ var str = ...
- 工具安装===Sublime Text-安装
Sublime Text 是一款通用型轻量级编辑器,支持多种编程语言.有许多功能强大的快捷键(如 Ctrl+d),支持丰富的插件扩展.如果平时需要在不同编程语言间切换,那么它将会是一个,不错的选择. ...
- Win10默认图片查看器更改
Win10自带的图片查看器不是很习惯,其背景乌漆嘛黑,宽扁的额头让人想起了黑边火腿肠手机,无法直视.怀念Win7和Win8.1的图片查看器,一个鼠标滚轮缩放自如的酸爽感觉.但却遗憾地发现,并不能直观地 ...
- UVA 11076 Add Again
题目链接:UVA-33478 题意为给定n个数,求这n个数能组成的所有不同的排列组成的数字的和. 思路:发现对于任意一个数字,其在每一位出现的次数是相同的.换言之,所有数字的每一位相加的和是相同的. ...
- 使用OC swift 截取路径中的最后的文件名
使用 OC swift 截取路径中的最后的文件名 如何截取下面路径中最后的文件名 AppDelegate.swift /Users/XXX/Desktop/Swift/swift02/code/02- ...
- 用JavaScript简单判断浏览器类型
判断浏览器类型 /** * 判断浏览器类型 * 返回表示浏览器类型的字符串 */ function whoIsMe(){ var explorer = navigator.userAgent; if( ...
- 虚拟机 VMware Workstation12 安装OS X 系统
Windows下虚拟机安装Mac OS X —– VMware Workstation12安装Mac OS X 10.11 本文即将介绍WIN虚拟MAC的教程.完整详细教程(包含安装中的一些问题) ...