Aizu 2450 Do use segment tree (树链剖分)
2015-10-02 19:46
453 查看
Aizu 2450 Do use segment tree
树链剖分 + 线段树区间更新,就是用线段树求区间最大连续子序列和。
求区间最大连续子序列和 的 区间更新 都很好实现。
要注意的是最后询问的时候多个区间合并的顺序和正反的问题(就是后面swap那儿)
一开始线段树初始化那儿写残了调了好久 - -
--------
孙大大的板子好长啊 - -
树链剖分 + 线段树区间更新,就是用线段树求区间最大连续子序列和。
求区间最大连续子序列和 的 区间更新 都很好实现。
要注意的是最后询问的时候多个区间合并的顺序和正反的问题(就是后面swap那儿)
一开始线段树初始化那儿写残了调了好久 - -
--------
孙大大的板子好长啊 - -
#include <bits/stdc++.h> #define lson num<<1 #define rson num<<1|1 #define gl l,m,lson #define gr m+1,r,rson #define PARA int l=L,int r=R,int num=1 using namespace std; const int MAXN = 2e5+100; const int INF = 0x2f2f2f2f; struct Node { long long lmx,rmx,mx,sum,tag; long long l,r; void init(int a,int b) { l=a,r=b; tag=INF; } void mark(long long v) { tag=v; sum=v*(r-l+1); mx=lmx=rmx=max(v,sum); } void merge(Node a, Node b) { lmx=max(max(a.lmx,a.sum),max(a.sum+b.lmx,a.sum+b.sum)); rmx=max(max(b.rmx,b.sum),max(b.sum+a.rmx,a.sum+b.sum)); sum=a.sum+b.sum; mx=max(max(max(lmx,rmx),max(a.mx,b.mx)),a.rmx+b.lmx); } void swap() { ::swap(lmx,rmx); } }; int L,R; struct SegTree { int num[MAXN]; Node st[MAXN<<2]; void pushUp(int num) { st[num].merge(st[lson],st[rson]); } void pushDown(int num) { long long &v=st[num].tag; int l=st[num].l,r=st[num].r; if(l!=r&&v!=INF) { st[lson].mark(v); st[rson].mark(v); pushUp(num); } v=INF; } void init(int v[],PARA) { int m=l+r>>1; st[num].init(l,r); if(l!=r) init(v,gl),init(v,gr),pushUp(num); else st[num].mark(v[l]); } void update(int a,int b,int v,PARA) { pushDown(num); if(a<=l&&r<=b) st[num].mark(v); else { int m=l+r>>1; if(b<=m) update(a,b,v,gl); else if(a>m) update(a,b,v,gr); else update(a,b,v,gl),update(a,b,v,gr); pushUp(num); } } Node query(int a,int b,PARA) { pushDown(num); Node ret; if(a<=l&&r<=b) return st[num]; int m=l+r>>1; if(b<=m) ret=query(a,b,gl); else if(a>m) ret=query(a,b,gr); else ret.merge(query(a,b,gl),query(a,b,gr)); pushUp(num); return ret; } } tr; const int maxn=MAXN; const int maxm=maxn+maxn; struct EDGENODE { int to; int next; } edges[maxm]; int head[maxn],edge; inline void init() { edge=0; memset(head,-1,sizeof(head)); } inline void addedge(int u,int v) { edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++; edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++; } int que[maxn]; // 队列 bool vis[maxn]; // 访问标记 int son[maxn]; // 重儿子 int idx[maxn]; // 结点v在其路径中的编号 int dep[maxn]; // 结点v的深度 int siz[maxn]; // 以结点v为根的子树的结点个数 int belong[maxn]; // 结点v所属的路径编号 int fa[maxn]; // 结点v的父亲结点 int top[maxn]; // 编号为p的路径的顶端结点 int len[maxn]; // 路径p的长度 int sump[maxn]; // 路径p的编号 int seg[maxn]; // 结点v的父边在线段树中的位置 int wei[maxn]; // 结点v的父边的权值 int l,r,ans,cnt; int n; char cmd[22]; void split() { memset(dep,-1,sizeof(dep)); l=0; dep[ que[r=1]=1 ]=0; // 将根结点插入队列,并设深度为0 fa[1]=-1; // 默认 1 为根结点 while (l<r) // 第一遍搜索求出 fa,dep,wei { int u=que[++l]; vis[u]=false; // 顺便初始化vis for (int i=head[u]; i!=-1; i=edges[i].next) { int v=edges[i].to; if (dep[v]==-1) // 未访问过的结点 { dep[ que[++r]=v ]=dep[u]+1; // 将v插入队列并设深度为dep[u]+1 fa[v]=u; // v的父结点为u } } } cnt=0; // 重链编号 for (int i=n; i>0; i--) { int u=que[i],p=-1; siz[u]=1; son[u]=p; for (int k=head[u]; k!=-1; k=edges[k].next) { int v=edges[k].to; if (vis[v]) // 若v是u的子结点 { siz[u]+=siz[v]; // 计数 if (p==-1||siz[v]>siz[p]) { son[u]=v; p=v; // u的重儿子是v } } } if (p==-1) // u是叶子结点 { idx[u]=len[++cnt]=1; // 一个新的路径编号为cnt,u是路径中的第一个结点 belong[ top[cnt]=u ]=cnt; // u是顶端结点,且u属于路径cnt } else // u不是叶子结点 { idx[u]=++len[ belong[u]=belong[p] ]; // u属于重儿子所在的链,链长+1,u是路径中第len个结点 top[ belong[u] ]=u; // u是顶端结点 } vis[u]=true; // 访问标记 } sump[0]=0; for (int i=1;i<=cnt;i++) sump[i]=sump[i-1]+len[i]; for (int i=1;i<=n;i++){ seg[i]=sump[ belong[i] ]-idx[i]+1; tr.num[ seg[i] ]=wei[i]; } } int in[MAXN]; void build() { int a,b; for(int i=1;i<=n;i++) scanf("%d",&wei[i]); for(int i=1;i<n;i++) scanf("%d%d",&a,&b),addedge(a,b); split(); for(int i=1;i<=n;i++) in[seg[i]]=wei[i]; L=1,R=n; tr.init(in); } Node q1[MAXN],q2[MAXN]; long long find(int va,int vb) { int f1=top[belong[va]],f2=top[belong[vb]]; int s1=0,s2=0; while (f1!=f2) { if (dep[f1]<dep[f2]) { q2[s2++]=tr.query(seg[f2],seg[vb]); vb=fa[f2]; f2=top[belong[vb]]; } else { q1[s1]=tr.query(seg[f1],seg[va]); q1[s1++].swap(); va=fa[f1]; f1=top[belong[va]]; } } for(int i=1;i<s1;i++) q1[0].merge(q1[0],q1[i]); for(int i=1;i<s2;i++) q2[0].merge(q2[i],q2[0]); int d=0; if (dep[va]>dep[vb]) swap(va,vb),d=1; Node ret=tr.query(seg[va],seg[vb]); if(d) ret.swap(); if(s1) ret.merge(q1[0],ret); if(s2) ret.merge(ret,q2[0]); return ret.mx; } void update(int va,int vb,int v){ int f1=top[belong[va]],f2=top[belong[vb]],tmp=-INF; while (f1!=f2){ if (dep[f1]<dep[f2]){ swap(f1,f2); swap(va,vb); } tr.update(seg[f1],seg[va],v); va=fa[f1]; f1=top[belong[va]]; } if (dep[va]>dep[vb]) swap(va,vb); tr.update(seg[va],seg[vb],v); } int main() { int q,a,b,c,d; while(scanf("%d%d",&n,&q)!=EOF) { init(); build(); for(int i=0;i<q;i++) { scanf("%d%d%d%d",&a,&b,&c,&d); if(a==1) update(b,c,d); else printf("%lld\n",find(b,c)); } } return 0; }
相关文章推荐
- LightOJ 1138 Trailing Zeroes (III)
- 11i - 12 Gather Schema Statistics fails with Ora-20001 errors after 11G database Upgrade (文档 ID 781813.1)
- Hdu 4681 2013 Multi-University Training Contest 8 String
- http://wenku.baidu.com/link?url=UGoPtZviipHzi5SDIlGx6hPFWAHTPLFXcZ7ieD15JMd81DEHqjehvphVMhqELmOK4qXR74dTT9nW8VBoApBc7Kfb1ZWrNF_i24fY1YRHVki
- Aizu 2456 Usoperanto (贪心)
- UVa 11853 PaintBall
- 在linux进程中的信号屏蔽 http://blog.csdn.net/fjb2080/article/details/5174306
- vfork http://blog.csdn.net/tennysonsky/article/details/45847107
- Light oj 1038 - Race to 1 Again(概率dp)
- Tail call optimization in Scala
- 信号量sem_wait()的使用
- 关于信号量sem_wait的整理(转)
- system()函数 http://blog.csdn.net/ghevinn/article/details/7916126
- waitpid系统调用在Linux函数库中的原型是:http://blog.sina.com.cn/s/blog_602a39250100xfxx.html
- poj2305-Basic remains(进制转换 + 大整数取模)
- HDU 1702 ACboy needs your help again!(栈和队列)
- poj 1995 Raising Modulo Numbers【快速幂】
- 解决:CWnd::SetWindowText报Assertion failure
- AIDL调用第三方应用程序服务中的方法
- wait函数返回值总结http://blog.csdn.net/astrotycoon/article/details/41172389