树链剖分学习笔记
来源:互联网 发布:热力计算软件 编辑:程序博客网 时间:2024/06/01 14:39
暂时搞完一系列字符串算法之后,开始了树链剖分算法的学习。
树链剖分算法,说白了就是一种特殊的DFS序(通过把节点分为重节点和轻节点来保证线段树的时间复杂度)然后在线段树上乱搞。
题目分为点权和边权两类,点权好理解一些,边权可以转化为边在树中指向节点的权值。网上博客挺多的,不一一赘述了。上习题。
ZJOI 2008 BZOJ 1036 COGS 1688 树的统计Count
点权的模板题,code:
w#include<iostream>#include<cstdio>#include<cstring>#define mid (l+r)/2#define lch i<<1,l,mid#define rch i<<1|1,mid+1,rusing namespace std;struct hp{int wson,fat,size,dep,top;}tree[30001];struct hq{int u,v;}a[60000];struct hr{int maxn,sum;}seg[120000];int plc[30001],f[30001],val[30001];int point[30000],next[60000];int n,e=1,totw=0,m,ans=-2100000000;void add(int u,int v){e++; a[e].u=u; a[e].v=v; next[e]=point[u]; point[u]=e;e++; a[e].u=v; a[e].v=u; next[e]=point[v]; point[v]=e;}void build_tree(int last,int x,int depth){int i;tree[x].dep=depth;tree[x].size=1;tree[x].fat=last;tree[x].wson=0;for (i=point[x];i;i=next[i]) if (a[i].v!=last) { build_tree(x,a[i].v,depth+1); tree[x].size+=tree[a[i].v].size; if (tree[tree[x].wson].size<tree[a[i].v].size) tree[x].wson=a[i].v; }}void build_seg(int now,int tp){int i;tree[now].top=tp;plc[now]=++totw;f[totw]=now;if (tree[now].wson!=0) build_seg(tree[now].wson,tp);for (i=point[now];i;i=next[i]) if (a[i].v!=tree[now].wson&&a[i].v!=tree[now].fat) build_seg(a[i].v,a[i].v);}void updata(int i){seg[i].maxn=max(seg[i<<1].maxn,seg[i<<1|1].maxn);seg[i].sum=seg[i<<1].sum+seg[i<<1|1].sum;}void build(int i,int l,int r){if (l==r) { seg[i].maxn=seg[i].sum=val[f[l]]; return; }build(lch); build(rch);updata(i);}void insert(int i,int l,int r,int x,int a){if (l==r&&l==x) { seg[i].maxn=seg[i].sum=a; return; }if (x<=mid) insert(lch,x,a);else insert(rch,x,a);updata(i);}void query_seg(int i,int l,int r,int x,int y,int kind){if (x<=l&&y>=r) { if (kind==0) ans=max(ans,seg[i].maxn); if (kind==1) ans=ans+seg[i].sum; return; }if (x<=mid) query_seg(lch,x,y,kind);if (y>mid) query_seg(rch,x,y,kind);}void query(int x,int y,int kind){int f1=tree[x].top,f2=tree[y].top;while (f1!=f2) { if (tree[f1].dep<tree[f2].dep) {swap(x,y); swap(f1,f2);} query_seg(1,1,n,plc[f1],plc[x],kind); x=tree[f1].fat; f1=tree[x].top; } if (tree[x].dep>tree[y].dep) swap(x,y);query_seg(1,1,n,plc[x],plc[y],kind);printf("%d\n",ans); }int main(){int i,x,y;char opt[10];scanf("%d",&n);for (i=1;i<=n-1;++i) { scanf("%d%d",&x,&y); add(x,y); }build_tree(0,1,0);build_seg(1,1);for (i=1;i<=n;++i) scanf("%d",&val[i]);build(1,1,n);scanf("%d",&m);for (i=1;i<=m;++i) { scanf("%s",&opt); if (opt[0]=='Q') { scanf("%d%d",&x,&y); if (opt[1]=='M') {ans=-2100000000;query(x,y,0);} if (opt[1]=='S') {ans=0;query(x,y,1);} } if (opt[0]=='C') { scanf("%d%d",&x,&y); insert(1,1,n,plc[x],y); } }}COGS 1672 SPOJ QTREE
蛮有名的边权树链剖分,code:
#include<iostream>#include<cstdio>#include<cstring>#define mid (l+r)/2#define lch i<<1,l,mid#define rch i<<1|1,mid+1,rusing namespace std;struct hp{int size,fat,top,wson,dep;}tree[10001];struct hr{int x,y,w;}qst[100001];struct hq{int u,v;}a[20001];int point[10001],next[20001];int plc[10001];int seg[40001],val[10001];int n,totw=0,e=1,ans=-2100000000;char s[10];void add(int u,int v){e++; a[e].u=u; a[e].v=v; next[e]=point[u]; point[u]=e;e++; a[e].u=v; a[e].v=u; next[e]=point[v]; point[v]=e;}void build_tree(int last,int x,int depth){int i;tree[x].size=1;tree[x].fat=last;tree[x].wson=0;tree[x].dep=depth;for (i=point[x];i;i=next[i]) if (a[i].v!=last) { build_tree(x,a[i].v,depth+1); tree[x].size+=tree[a[i].v].size; if (tree[tree[x].wson].size<tree[a[i].v].size) tree[x].wson=a[i].v; }}void build_seg(int now,int tp){int i;tree[now].top=tp;plc[now]=++totw;if (tree[now].wson!=0) build_seg(tree[now].wson,tp);for (i=point[now];i;i=next[i]) if (a[i].v!=tree[now].wson&&a[i].v!=tree[now].fat) build_seg(a[i].v,a[i].v);}void updata(int i){seg[i]=max(seg[i<<1],seg[i<<1|1]);}void build(int i,int l,int r){if (l==r) { seg[i]=val[l]; return; }build(lch); build(rch);updata(i);}void insert(int i,int l,int r,int x,int a){if (l==r&&l==x) { seg[i]=a; return; }if (x<=mid) insert(lch,x,a);else insert(rch,x,a);updata(i);}void query_seg(int i,int l,int r,int x,int y){if (x<=l&&y>=r) { ans=max(ans,seg[i]); return; }if (x<=mid) query_seg(lch,x,y);if (y>mid) query_seg(rch,x,y);}void query(int x,int y){int f1=tree[x].top,f2=tree[y].top;while (f1!=f2) { if (tree[f1].dep<tree[f2].dep) {swap(f1,f2); swap(x,y);} query_seg(1,1,n,plc[f1],plc[x]); x=tree[f1].fat; f1=tree[x].top; }if (x==y) printf("%d\n",ans);else { if (tree[x].dep>tree[y].dep) swap(x,y); query_seg(1,1,n,plc[tree[x].wson],plc[y]); printf("%d\n",ans); }}int main(){int i,z,x,y;freopen("qtree.in","r",stdin);freopen("qtree.out","w",stdout);scanf("%d",&n);for (i=1;i<=n-1;++i) { scanf("%d%d%d",&qst[i].x,&qst[i].y,&qst[i].w); add(qst[i].x,qst[i].y); }build_tree(0,1,0);build_seg(1,1);for (i=1;i<=n;++i) { if (tree[qst[i].x].dep<tree[qst[i].y].dep) swap(qst[i].x,qst[i].y); val[plc[qst[i].x]]=qst[i].w; }build(1,1,n);scanf("%s",&s);while (s[0]!='D') { scanf("%d%d",&x,&y); if (s[0]=='C') insert(1,1,n,plc[qst[x].x],y);if (s[0]=='Q') { ans=-2100000000; query(x,y); } scanf("%s",&s); }fclose(stdin);fclose(stdout);}BZOJ 2157 COGS 1867 国家集训队2011 旅游
这题唯一不同于模板的地方在于线段树的操作,negate相当让maxn=-minn,minn=-maxn,然后这题没了code:
#include<iostream>#include<cstdio>#include<cstring>#define mid (l+r)/2#define lch i<<1,l,mid#define rch i<<1|1,mid+1,r#define inf 2100000000using namespace std;struct hp{int size,top,fat,dep,wson;}tree[100001];struct hq{int x,y,w;}qst[500001];struct hr{int u,v;}a[200001];struct ht{int maxn,minn,f,sum;}seg[400001];int point[100001],next[200001];int plc[100001],val[100001];int n,ans,e=1,totw=0,m;void add(int x,int y){e++; a[e].u=x; a[e].v=y; next[e]=point[x]; point[x]=e;e++; a[e].v=x; a[e].u=x; next[e]=point[y]; point[y]=e;}void build_tree(int last,int x,int depth){int i;tree[x].size=1;tree[x].fat=last;tree[x].wson=0;tree[x].dep=depth;for (i=point[x];i;i=next[i]) if (a[i].v!=last) { build_tree(x,a[i].v,depth+1); tree[x].size+=tree[a[i].v].size; if (tree[tree[x].wson].size<tree[a[i].v].size) tree[x].wson=a[i].v; }}void build_seg(int now,int tp){int i;tree[now].top=tp;plc[now]=++totw;if (tree[now].wson!=0) build_seg(tree[now].wson,tp);for (i=point[now];i;i=next[i]) if (a[i].v!=tree[now].fat&&a[i].v!=tree[now].wson) build_seg(a[i].v,a[i].v);}void updata(int i){seg[i].maxn=max(seg[i<<1].maxn,seg[i<<1|1].maxn);seg[i].minn=min(seg[i<<1].minn,seg[i<<1|1].minn);seg[i].sum=seg[i<<1].sum+seg[i<<1|1].sum;}void paint(int i){int x=seg[i].minn,y=seg[i].maxn;seg[i].maxn=-x; seg[i].minn=-y;seg[i].sum=-seg[i].sum;seg[i].f++;}void pushdown(int i){paint(i<<1); paint(i<<1|1);seg[i].f=0;}void build(int i,int l,int r){if (l==r) { seg[i].maxn=seg[i].sum=seg[i].minn=val[l]; return; }build(lch); build(rch);updata(i);}void insert(int i,int l,int r,int x,int a){if (l==r&&l==x) { seg[i].maxn=seg[i].minn=seg[i].sum=a; return; }if (seg[i].f%2) pushdown(i);if (x<=mid) insert(lch,x,a);else insert(rch,x,a);updata(i);}void query(int i,int l,int r,int x,int y,int kind){if (x<=l&&y>=r) { if (kind==1) ans=ans+seg[i].sum; if (kind==2) ans=max(ans,seg[i].maxn); if (kind==3) ans=min(ans,seg[i].minn); return; }if (seg[i].f%2) pushdown(i);if (x<=mid) query(lch,x,y,kind);if (y>mid) query(rch,x,y,kind);}void opst(int i,int l,int r,int x,int y){if (x<=l&&y>=r) { paint(i); return; }if (seg[i].f%2) pushdown(i);if (x<=mid) opst(lch,x,y);if (y>mid) opst(rch,x,y);updata(i); }void work(int x,int y,int kind){int f1=tree[x].top,f2=tree[y].top;if (kind==1) ans=0;if (kind==2) ans=-inf;if (kind==3) ans=inf;while (f1!=f2) { if (tree[f1].dep<tree[f2].dep) {swap(f1,f2);swap(x,y);} if (kind==0) opst(1,1,n,plc[f1],plc[x]); else query(1,1,n,plc[f1],plc[x],kind); x=tree[f1].fat; f1=tree[x].top; }if (x!=y) { if (tree[x].dep>tree[y].dep) swap(x,y); if (kind==0) opst(1,1,n,plc[tree[x].wson],plc[y]); else query(1,1,n,plc[tree[x].wson],plc[y],kind); } if (kind>0) printf("%d\n",ans);}int main(){int i,x,y;char s[10];scanf("%d",&n);for (i=1;i<=n-1;++i) { scanf("%d%d%d",&qst[i].x,&qst[i].y,&qst[i].w); qst[i].x++; qst[i].y++; add(qst[i].x,qst[i].y); }build_tree(0,1,0);build_seg(1,1);for (i=1;i<=n-1;++i) { if (tree[qst[i].x].dep<tree[qst[i].y].dep) swap(qst[i].x,qst[i].y); val[plc[qst[i].x]]=qst[i].w; }build(1,1,n);scanf("%d",&m);for (i=1;i<=m;++i) { scanf("%*c%s%d%d",&s,&x,&y); if (s[0]!='C') {x++; y++;} if (s[0]=='N') work(x,y,0);if (s[0]=='C') insert(1,1,n,plc[qst[x].x],y);if (s[0]=='S') work(x,y,1);if (s[0]=='M') { if (s[1]=='A') work(x,y,2); if (s[1]=='I') work(x,y,3); } }}HAOI 2015 BZOJ 4034 COGS 1963 树上操作
考虑链剖其实是一种特殊的DFS序,那么一个点的子树必定在线段树里是连续的,在build_seg里更新一下最左最右位置即可。code:
#include<iostream>#include<cstdio>#include<cstring>#define mid (l+r)/2#define lch i<<1,l,mid#define rch i<<1|1,mid+1,r#define inf 2100000000using namespace std;struct hp{int size,wson,top,fat,dep,l,r;}tree[100001];struct hq{int u,v;}a[200001];int point[100001],next[200001];int val[100001],plc[100001],f[100001];long long seg[400001],delta[400001];int n,m,totw=0,e=1;long long ans;void add(int x,int y){e++; a[e].u=x; a[e].v=y; next[e]=point[x]; point[x]=e;e++; a[e].v=x; a[e].u=y; next[e]=point[y]; point[y]=e;}void build_tree(int last,int x,int depth){int i;tree[x].size=1;tree[x].wson=0;tree[x].fat=last;tree[x].dep=depth;for (i=point[x];i;i=next[i]) if (a[i].v!=last) { build_tree(x,a[i].v,depth+1); tree[x].size+=tree[a[i].v].size; if (tree[tree[x].wson].size<tree[a[i].v].size) tree[x].wson=a[i].v; }}void build_seg(int now,int tp){int i;tree[now].top=tp;tree[now].l=plc[now]=++totw;f[totw]=now;if (tree[now].wson!=0) build_seg(tree[now].wson,tp);for (i=point[now];i;i=next[i]) if (a[i].v!=tree[now].wson&&a[i].v!=tree[now].fat) build_seg(a[i].v,a[i].v);tree[now].r=totw;}void updata(int i){seg[i]=seg[i<<1]+seg[i<<1|1];}void build(int i,int l,int r){if (l==r) { seg[i]=val[f[l]];return; }build(lch); build(rch);updata(i);}void paint(int i,int l,int r,long long a){seg[i]=(long long)((long long)((long long)(r-l+1)*(long long)(a))+seg[i]);delta[i]=(long long)((long long)(a)+(long long)(delta[i]));}void pushdown(int i,int l,int r){paint(lch,delta[i]);paint(rch,delta[i]);delta[i]=0;}void query_seg(int i,int l,int r,int x,int y){if (x<=l&&y>=r) { ans=(long long)ans+(long long)seg[i]; return; }if (delta[i]!=0) pushdown(i,l,r);if (x<=mid) query_seg(lch,x,y);if (y>mid) query_seg(rch,x,y);}void insert(int i,int l,int r,int x,int y,int a){if (x<=l&&y>=r) { paint(i,l,r,a); return; }if (delta[i]!=0) pushdown(i,l,r);if (x<=mid) insert(lch,x,y,a);if (y>mid) insert(rch,x,y,a);updata(i);}void query(int x,int y){int f1=tree[x].top,f2=tree[y].top;ans=0;while (f1!=f2) { if (tree[f1].dep<tree[f2].dep) {swap(f1,f2); swap(x,y);} query_seg(1,1,n,plc[f1],plc[x]); x=tree[f1].fat; f1=tree[x].top; }if (tree[x].dep>tree[y].dep) swap(x,y);query_seg(1,1,n,plc[x],plc[y]);printf("%lld\n",ans);}int main(){int i,x,y,opt;scanf("%d%d",&n,&m);for (i=1;i<=n;++i) scanf("%d",&val[i]);for (i=1;i<=n-1;++i) { scanf("%d%d",&x,&y); add(x,y); }build_tree(0,1,0);build_seg(1,1);build(1,1,n);for (i=1;i<=m;++i) { scanf("%d",&opt); if (opt==1) { scanf("%d%d",&x,&y); insert(1,1,n,plc[x],plc[x],y); } if (opt==2) { scanf("%d%d",&x,&y); insert(1,1,n,tree[x].l,tree[x].r,y); } if (opt==3) { scanf("%d",&x); query(1,x); } }}SDOI 2011 BZOJ 2243 染色
链剖与前几道题是一样的,唯一多出来的就是线段树左右端点颜色的分类讨论,(PS:逗比把rightc写成leftc插了一个多小时= =)code:
#include<iostream>#include<cstdio>#include<cstring>#define mid (l+r)/2#define lch i<<1,l,mid#define rch i<<1|1,mid+1,rusing namespace std;struct hp{int size,fat,dep,wson,top;}tree[100001];struct hq{int u,v;}a[200001];struct hr{int lc,rc,sum,delta;}seg[400001];int point[100001],next[200001];int val[100001],f[100001],plc[100001];int n,m,totw=0,ans,e=1,leftc,rightc;void add(int x,int y){e++; a[e].u=x; a[e].v=y; next[e]=point[x]; point[x]=e;e++; a[e].u=y; a[e].v=x; next[e]=point[y]; point[y]=e;}void build_tree(int last,int x,int depth){int i;tree[x].size=1;tree[x].dep=depth;tree[x].fat=last;tree[x].wson=0;for (i=point[x];i;i=next[i]) if (a[i].v!=last) { build_tree(x,a[i].v,depth+1); tree[x].size+=tree[a[i].v].size; if (tree[tree[x].wson].size<tree[a[i].v].size) tree[x].wson=a[i].v; }}void build_seg(int now,int tp){int i;tree[now].top=tp;plc[now]=++totw; f[totw]=now;if (tree[now].wson!=0) build_seg(tree[now].wson,tp);for (i=point[now];i;i=next[i]) if (a[i].v!=tree[now].wson&&a[i].v!=tree[now].fat) build_seg(a[i].v,a[i].v);}void updata(int i){seg[i].lc=seg[i<<1].lc; seg[i].rc=seg[i<<1|1].rc;if (seg[i<<1].rc!=seg[i<<1|1].lc) seg[i].sum=seg[i<<1].sum+seg[i<<1|1].sum;else seg[i].sum=seg[i<<1].sum+seg[i<<1|1].sum-1;}void paint(int i,int a){seg[i].lc=seg[i].rc=a; seg[i].sum=1;seg[i].delta=a;}void pushdown(int i){paint(i<<1,seg[i].delta);paint(i<<1|1,seg[i].delta);seg[i].delta=-1;}void build(int i,int l,int r){seg[i].delta=-1;if (l==r) { seg[i].lc=seg[i].rc=val[f[l]];seg[i].sum=1;return; }build(lch); build(rch);updata(i);}void insert_seg(int i,int l,int r,int x,int y,int a){if (x<=l&&y>=r) { paint(i,a); return; }if (seg[i].delta!=-1) pushdown(i);if (x<=mid) insert_seg(lch,x,y,a);if (y>mid) insert_seg(rch,x,y,a);updata(i);}void insert(int x,int y,int z){int f1=tree[x].top,f2=tree[y].top;while (f1!=f2) { if (tree[f1].dep<tree[f2].dep) {swap(f1,f2); swap(x,y);} insert_seg(1,1,n,plc[f1],plc[x],z); x=tree[f1].fat; f1=tree[x].top; }if (tree[x].dep>tree[y].dep) swap(x,y);insert_seg(1,1,n,plc[x],plc[y],z);}void query_seg(int i,int l,int r,int x,int y){int lc,rc;if (l==x) leftc=seg[i].lc; if (r==y) rightc=seg[i].rc;if (x<=l&&y>=r) { ans+=seg[i].sum; return; }if (seg[i].delta!=-1) pushdown(i);lc=-1; rc=-1;if (x<=mid) {query_seg(lch,x,y);lc=seg[i<<1].rc;}if (y>mid) {query_seg(rch,x,y);rc=seg[i<<1|1].lc;}if (lc==rc&&lc!=-1&&rc!=-1) ans--;}void query(int x,int y){int f1=tree[x].top,f2=tree[y].top,tot=0;int lcr=-1,rcr=-1; ans=0;while (f1!=f2) { if (tree[f1].dep<tree[f2].dep) { query_seg(1,1,n,plc[f2],plc[y]); if (rcr==rightc) ans--; rcr=leftc; y=tree[f2].fat; f2=tree[y].top; } else { query_seg(1,1,n,plc[f1],plc[x]); if (lcr==rightc) ans--; lcr=leftc; x=tree[f1].fat; f1=tree[x].top; } }if (tree[x].dep<tree[y].dep) { query_seg(1,1,n,plc[x],plc[y]); if (rcr==rightc) ans--; if (lcr==leftc) ans--; }else { query_seg(1,1,n,plc[y],plc[x]); if (rcr==leftc) ans--; if (lcr==rightc) ans--; }printf("%d\n",ans);}int main(){int i,x,y,z;char c;scanf("%d%d",&n,&m);for (i=1;i<=n;++i) scanf("%d",&val[i]);for (i=1;i<=n-1;++i) { scanf("%d%d",&x,&y); add(x,y); }build_tree(0,1,0);build_seg(1,1);build(1,1,n);for (i=1;i<=m;++i) { scanf("%c",&c); while (c!='C'&&c!='Q') scanf("%c",&c); if (c=='C') { scanf("%d%d%d",&x,&y,&z); insert(x,y,z); } if (c=='Q') { scanf("%d%d",&x,&y); query(x,y); } }}SDOI 2014 BZOJ 3531 旅行
这题自己一开始的想法是按每种宗教建一棵线段树,内存炸的飞起,看完黄学长的博客才焕然大悟,其实只需要对每种宗教建一棵局部线段树即可。code:
#include<iostream>#include<cstdio>#include<cstring>#define mid (l+r)/2#define lch i<<1,l,mid#define rch i<<1|1,mid+1,rusing namespace std;struct hp{int size,fat,dep,wson,top;}tree[100001];struct hq{int u,v;}a[200001];struct hr{int lc,rc,sum,delta;}seg[400001];int point[100001],next[200001];int val[100001],f[100001],plc[100001];int n,m,totw=0,ans,e=1,leftc,rightc;void add(int x,int y){e++; a[e].u=x; a[e].v=y; next[e]=point[x]; point[x]=e;e++; a[e].u=y; a[e].v=x; next[e]=point[y]; point[y]=e;}void build_tree(int last,int x,int depth){int i;tree[x].size=1;tree[x].dep=depth;tree[x].fat=last;tree[x].wson=0;for (i=point[x];i;i=next[i]) if (a[i].v!=last) { build_tree(x,a[i].v,depth+1); tree[x].size+=tree[a[i].v].size; if (tree[tree[x].wson].size<tree[a[i].v].size) tree[x].wson=a[i].v; }}void build_seg(int now,int tp){int i;tree[now].top=tp;plc[now]=++totw; f[totw]=now;if (tree[now].wson!=0) build_seg(tree[now].wson,tp);for (i=point[now];i;i=next[i]) if (a[i].v!=tree[now].wson&&a[i].v!=tree[now].fat) build_seg(a[i].v,a[i].v);}void updata(int i){seg[i].lc=seg[i<<1].lc; seg[i].rc=seg[i<<1|1].rc;if (seg[i<<1].rc!=seg[i<<1|1].lc) seg[i].sum=seg[i<<1].sum+seg[i<<1|1].sum;else seg[i].sum=seg[i<<1].sum+seg[i<<1|1].sum-1;}void paint(int i,int a){seg[i].lc=seg[i].rc=a; seg[i].sum=1;seg[i].delta=a;}void pushdown(int i){paint(i<<1,seg[i].delta);paint(i<<1|1,seg[i].delta);seg[i].delta=-1;}void build(int i,int l,int r){seg[i].delta=-1;if (l==r) { seg[i].lc=seg[i].rc=val[f[l]];seg[i].sum=1;return; }build(lch); build(rch);updata(i);}void insert_seg(int i,int l,int r,int x,int y,int a){if (x<=l&&y>=r) { paint(i,a); return; }if (seg[i].delta!=-1) pushdown(i);if (x<=mid) insert_seg(lch,x,y,a);if (y>mid) insert_seg(rch,x,y,a);updata(i);}void insert(int x,int y,int z){int f1=tree[x].top,f2=tree[y].top;while (f1!=f2) { if (tree[f1].dep<tree[f2].dep) {swap(f1,f2); swap(x,y);} insert_seg(1,1,n,plc[f1],plc[x],z); x=tree[f1].fat; f1=tree[x].top; }if (tree[x].dep>tree[y].dep) swap(x,y);insert_seg(1,1,n,plc[x],plc[y],z);}void query_seg(int i,int l,int r,int x,int y){int lc,rc;if (l==x) leftc=seg[i].lc; if (r==y) rightc=seg[i].rc;if (x<=l&&y>=r) { ans+=seg[i].sum; return; }if (seg[i].delta!=-1) pushdown(i);lc=-1; rc=-1;if (x<=mid) {query_seg(lch,x,y);lc=seg[i<<1].rc;}if (y>mid) {query_seg(rch,x,y);rc=seg[i<<1|1].lc;}if (lc==rc&&lc!=-1&&rc!=-1) ans--;}void query(int x,int y){int f1=tree[x].top,f2=tree[y].top,tot=0;int lcr=-1,rcr=-1; ans=0;while (f1!=f2) { if (tree[f1].dep<tree[f2].dep) { query_seg(1,1,n,plc[f2],plc[y]); if (rcr==rightc) ans--; rcr=leftc; y=tree[f2].fat; f2=tree[y].top; } else { query_seg(1,1,n,plc[f1],plc[x]); if (lcr==rightc) ans--; lcr=leftc; x=tree[f1].fat; f1=tree[x].top; } }if (tree[x].dep<tree[y].dep) { query_seg(1,1,n,plc[x],plc[y]); if (rcr==rightc) ans--; if (lcr==leftc) ans--; }else { query_seg(1,1,n,plc[y],plc[x]); if (rcr==leftc) ans--; if (lcr==rightc) ans--; }printf("%d\n",ans);}int main(){int i,x,y,z;char c;scanf("%d%d",&n,&m);for (i=1;i<=n;++i) scanf("%d",&val[i]);for (i=1;i<=n-1;++i) { scanf("%d%d",&x,&y); add(x,y); }build_tree(0,1,0);build_seg(1,1);build(1,1,n);for (i=1;i<=m;++i) { scanf("%c",&c); while (c!='C'&&c!='Q') scanf("%c",&c); if (c=='C') { scanf("%d%d%d",&x,&y,&z); insert(x,y,z); } if (c=='Q') { scanf("%d%d",&x,&y); query(x,y); } }}
0 0
- 学习笔记: 树链剖分
- 树链剖分学习笔记
- 树链剖分学习笔记
- 树链剖分学习笔记
- 学习笔记--树链剖分
- 树链剖分学习笔记
- 树链剖分学习笔记
- 树链剖分学习笔记
- 【树链剖分】学习笔记
- 树链剖分学习笔记
- 树链剖分学习笔记
- 树链剖分学习笔记 && SPOJ QTREE
- |算法讨论|树链剖分 学习笔记
- 学习笔记?
- 学习笔记
- 学习笔记
- 学习笔记
- 学习笔记
- 斐波那契数列权值
- 特殊数据类型成员变量的初始化
- sgu216:Royal Federation(构造)
- OSG+QT5+vs2010编译
- java 线程间的通信 pipedOutStream 和PipedInputStream 管道流
- 树链剖分学习笔记
- 调整数组顺序使奇数位于偶数前面
- HDU-1528 Card Game Cheater
- LabelReader分析
- Euler: Integer right triangles
- Lucene学习笔记(二)——搜索,分词
- 精选30道Java笔试题解答
- [leetcode][回溯] Combination Sum
- 非常牛比的网站