Aizu 2450 Do use segment tree (树链剖分)
来源:互联网 发布:杨子天珠淘宝店 编辑:程序博客网 时间:2024/05/22 04:36
Aizu 2450 Do use segment tree
树链剖分 + 线段树区间更新,就是用线段树求区间最大连续子序列和。
求区间最大连续子序列和 的 区间更新 都很好实现。
要注意的是最后询问的时候多个区间合并的顺序和正反的问题(就是后面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=1using 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;}
0 0
- Aizu 2450 Do use segment tree (树链剖分)
- Aizu 2450 Do use segment tree LCT
- Aoj 2450 Do use segment tree【树链剖分】
- bnuoj 39566 Do use segment tree(树链剖分)
- aoj2450 Do use segment tree 树链剖分
- AOJ 2450 Do use segment tree (树链剖分 + 线段树区间合并)
- Do use segment tree 树链剖分,按顺序剖分
- BNUOJ 39566 Do use segment tree(树链剖分——点权)
- BNUOJ39566 Do use segment tree (树链剖分+维护区间最大连续和)
- 树链剖分 JAG Summer 2012 Day 4 D Do use segment tree
- 线段树(segment tree)
- 线段树(Segment Tree)
- 线段树(segment tree)
- 区间树(segment tree)
- Codeforces755D (segment tree,implementation)
- segment tree(线段树)
- Segment Tree(线段树)
- 线段树(segment tree)
- 重写setter与getter方法以及其使用情况
- C++学习笔记之类模板
- 用jquery实现全选功能
- android-Day01(常用命令、像素)
- HDU 5203 Rikka with wood sticks
- Aizu 2450 Do use segment tree (树链剖分)
- mobius HDOJ 5468 Puzzled Elena
- SimpleCalculator
- java字符串与整数之间的互相转换
- 第四周--项目1
- Mysql 5.6.22编译安装
- Picasso分析02
- 03crawler01 爬取直播电视剧列表
- 你所厌恶的正是别人渴望的