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的边权 ...
随机推荐
- NGINX: 反向代理 Nexus
Nginx 反向代理 nexus 的服务, 一直卡在 Initialize... 解决方式是添加一个 header X-Forwarded-Proto: proxy_set_header X-Forw ...
- bootstrap 弹窗 数据清除
bootstrap modal操作简单易用, //清除弹窗原数据 $("#create_modal").on("hidden.bs.modal", functi ...
- 浅谈游戏中BUFF的设计要点
其实这类帖子并没有多少的设计理论,对于策划的提升和帮助也并不大,原因其实在于其适用性太窄,当我要设计XX象棋的时候,它就滚一边去了. 废话不多说切入正题: 游戏中的BUFF/DEBUFF我们见过很多, ...
- 安装FFMpeg CentOS 7
https://linuxadmin.io/install-ffmpeg-on-centos-7/
- python实战===一键刷屏
#当按键q的时候,自动输入 “大家好!”并回车键发送!from pynput import keyboard from pynput.keyboard import Key, Controller k ...
- gnu app url[web][5星]
http://www.gnu.org/software/software.zh-cn.html http://linux.chinaunix.net/news/2010/12/07/1175310.s ...
- Oracle例外定义
例外名 ORA-XXXXX SQLCODE ACCESS_INTO_NULL ORA-06530 -6530 CASE_NOT_FOUND ORA-06592 -6592 COLLECTION_IS_ ...
- linux命令(42):wc命令
Linux系统中的wc(Word Count)命令的功能为统计指定文件中的字节数.字数.行数,并将统计结果显示输出. 1.命令格式: wc [选项]文件... 2.命令功能: 统计指定文件中的字节数. ...
- Fel表达式使用过程中需要注意的问题
精度问题: 我们知道java中直接使用float和double参与的计算都可能会产生精度问题,比如0.1+0.3.1.0-0.9 等.所以一般财务系统,都会使用BigDecimal进行加减乘除. 在调 ...
- LeetCode解题报告—— Reverse Linked List II & Restore IP Addresses & Unique Binary Search Trees II
1. Reverse Linked List II Reverse a linked list from position m to n. Do it in-place and in one-pass ...