树链剖分学习笔记

来源:互联网 发布:热力计算软件 编辑:程序博客网 时间: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
原创粉丝点击