洛谷P3384 树链剖分

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

                    --by洛谷



一听名字就知道是模板;

有关树链剖分的内容

对子树操作,可理解为对dfs序上fa开头长度为子树size的区间操作;

代码如下:

  1 #include<cstdio>
  2 using namespace std;
  3 int n,m,r,L,R;
  4 int p,Z;
  5 int dis[100001];
  6 int ltree[400001];
  7 int      lz[400001];
  8 int dep[100001],fa[100001],hine[100001],size[100001];
  9 int top[100001],a[100001],rank[100001];
 10 struct ss{
 11     int to,next;
 12 }x[200001];
 13 int first[200001],num;
 14 void build(int ,int );
 15 void dfs_1(int );
 16 void dfs_2(int ,int );
 17 void up(int );
 18 void down(int ,int ,int );
 19 void builine(int ,int ,int );
 20 void swap(int&,int&);
 21 void work1(int );
 22 void work2(int );
 23 void add(int ,int ,int );
 24 int sum(int ,int ,int );
 25 int main()
 26 {
 27     int i,j,k;
 28     scanf("%d%d%d%d",&n,&m,&r,&p);
 29     for(i=1;i<=n;i++)
 30         scanf("%d",&dis[i]),dis[i]%=p,hine[i]=i;
 31     for(i=1;i<=n-1;i++){
 32         scanf("%d%d",&j,&k);
 33         build(j,k);
 34         build(k,j);
 35     }
 36     dep[r]=1;
 37     dfs_1(r);
 38     num=0;
 39     dfs_2(r,r);
 40     num=0;
 41     builine(1,n,1);
 42     for(i=1;i<=m;i++){
 43         scanf("%d",&j);
 44         if(j<=2)work1(j);
 45         else    work2(j-2);
 46     }
 47 }
 48 void build(int f,int t){
 49     x[++num].next=first[f];
 50     x[num].to=t;
 51     first[f]=num;
 52 }
 53 void dfs_1(int now){
 54     int j=first[now];
 55     while(j){
 56         if(!dep[x[j].to]){
 57             dep[x[j].to]=dep[now]+1;
 58             fa[x[j].to]=now;
 59             dfs_1(x[j].to);
 60             size[now]+=size[x[j].to];
 61             if(hine[now]==now||size[x[j].to]>size[hine[now]])
 62                 hine[now]=x[j].to;
 63         }
 64         j=x[j].next;
 65     }
 66     size[now]++;
 67 }
 68 void dfs_2(int now,int top_now){
 69     int j=first[now];
 70     top[now]=top_now;
 71     a[++num]=now;
 72     rank[now]=num;
 73     if(hine[now]!=now)
 74         dfs_2(hine[now],top_now);
 75     while(j){
 76         if(dep[x[j].to]==dep[now]+1&&x[j].to!=hine[now])
 77             dfs_2(x[j].to,x[j].to);
 78         j=x[j].next;
 79     }
 80 }
 81 void up(int nu){
 82     ltree[nu]=ltree[nu<<1]+ltree[nu<<1|1];
 83 }
 84 void down(int l,int r,int nu){
 85     if(!lz[nu])return ;
 86     int mid=(l+r)>>1;
 87     lz[nu<<1]=(lz[nu<<1]+lz[nu])%p;
 88     lz[nu<<1|1]=(lz[nu<<1|1]+lz[nu])%p;
 89     ltree[nu<<1]=(ltree[nu<<1]+lz[nu]*(mid-l+1))%p;
 90     ltree[nu<<1|1]=(ltree[nu<<1|1]+lz[nu]*(r-mid))%p;
 91     lz[nu]=0;
 92 }
 93 void builine(int l,int r,int nu){
 94     if(l==r){
 95         ltree[nu]=dis[a[++num]];
 96         return;
 97     }
 98     int mid=(l+r)>>1;
 99     builine(l,mid,nu<<1);
100     builine(mid+1,r,nu<<1|1);
101     up(nu);
102 }
103 void swap(int&a,int&b){
104     int c=a;a=b;b=c;
105 }
106 void work1(int x){
107     int u,v,ans=0;
108     scanf("%d%d",&u,&v);
109     if(x==1)scanf("%d",&Z);
110     while(top[u]!=top[v]){
111         if(dep[top[u]]>dep[top[v]])
112             L=rank[top[u]],R=rank[u],u=fa[top[u]];
113         else
114             L=rank[top[v]],R=rank[v],v=fa[top[v]];
115         if(x==1)
116             add(1,n,1);
117         else
118             ans=(ans+sum(1,n,1))%p;
119     }
120 //    if(u!=v){
121     if(dep[u]>dep[v])
122         swap(u,v);
123     L=rank[u];R=rank[v];
124     if(x==1)
125         add(1,n,1);
126     else
127         ans=(ans+sum(1,n,1))%p;
128 //    }
129     if(x==2)
130         printf("%d
",ans);
131 }
132 void work2(int x){
133     int ans=0,i;
134     scanf("%d",&i);
135     L=rank[i];R=L+size[i]-1;
136     if(x==1)scanf("%d",&Z);
137         if(x==1)
138             add(1,n,1);
139         else
140             ans=(ans+sum(1,n,1))%p,printf("%d
",ans);
141 }
142 void add(int l,int r,int nu){
143     if(L<=l&&r<=R){
144         ltree[nu]=(ltree[nu]+(r-l+1)*Z)%p;
145         lz[nu]=(lz[nu]+Z)%p;
146         return ;
147     }
148     int mid=(l+r)>>1;
149     down(l,r,nu);
150     if(L<=mid)
151         add(l,mid,nu<<1);
152     if(R>mid)
153         add(mid+1,r,nu<<1|1);
154     up(nu);
155 }
156 int sum(int l,int r,int nu){
157     if(L<=l&&r<=R)
158         return ltree[nu];
159     int mid=(l+r)>>1,ans=0;
160     down(l,r,nu);
161     if(L<=mid)
162         ans=(ans+sum(l,mid,nu<<1))%p;
163     if(R>mid)
164         ans=(ans+sum(mid+1,r,nu<<1|1))%p;
165     return ans;
166 }

祝AC哟!

原文地址:https://www.cnblogs.com/nietzsche-oier/p/6386278.html