【模板】轻重链剖分

可以算是此题的进阶

题目描述

如题,已知一棵包含 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 为根节点的子树内所有节点值之和

输入格式

第一行包含 4 个正整数 N,M,R,P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含 N 个非负整数,分别依次表示各个节点上初始的数值。

接下来 N1 行每行包含两个整数 x,y,表示点 x 和点 y 之间连有一条边(保证无环且连通)。

接下来 M 行每行包含若干个正整数,每行表示一个操作,格式如下:

操作 1: 1 x y z;

操作 2: 2 x y;

操作 3: 3 x z;

操作 4: 4 x。

输出格式

输出包含若干行,分别依次表示每个操作 22 或操作 44 所得的结果(对 PP 取模)。

输入输出样例

输入 #1
5 5 2 24
7 3 7 8 0 
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
输出 #1
2
21

说明/提示

数据规模:

对于 30% 的数据: 1N10,1M10;

对于 70% 的数据: 1N10^3,1M10^3;

对于 100% 的数据: 1N10^5,1M10^5,1RN,1P2^311。

样例说明:

树的结构如下:

各个操作如下:

故输出应依次为 2 和 21


 

有时间再解释吧,先放个代码

  1 /*
  2 5 5 2 24
  3 7 3 7 8 0 
  4 1 2
  5 1 5
  6 3 1
  7 4 1
  8 3 4 2
  9 3 2 2
 10 4 5
 11 1 5 1 3
 12 2 1 3
 13 */
 14 #include<iostream>
 15 #include<cstring>
 16 #include<cstdio>
 17 #include<cmath>
 18 using namespace std;
 19 int dep[1000001]={0},dad[1000001]={0},size[1000001]={0},heavy_son[1000001]={0};
 20 int cnt=0,N,Mod,n,m,s;
 21 int top[1000001]={0},last[1000001]={0},v[1000001]={0};
 22 int new_id[1000001]={0},old_id[1000001]={0},tree[1000001]={0},lazy[1000001]={0};
 23 struct node{
 24     int to,next;
 25 }line[1000001];
 26 int add(int add_u,int add_v){
 27     line[++N].to=add_v;
 28     line[N].next=last[add_u];
 29     last[add_u]=N;
 30 }
 31 int Max(int max_x,int max_y){
 32     if(max_x<max_y) return max_y;
 33     return max_x;
 34 }
 35 int Min(int min_x,int min_y){
 36     if(min_x>min_y) return min_y;
 37     return min_x;
 38 }
 39 int dfs1(int F,int root,int deep){
 40     dep[root]=deep;
 41     dad[root]=F;
 42     size[root]=1;
 43     int maxn=0;
 44     for(int i=last[root];i;i=line[i].next){
 45         int To=line[i].to;
 46         if(F==To) continue;
 47         dfs1(root,To,deep+1);
 48         size[root]+=size[To];
 49         if(size[To]>maxn){
 50             heavy_son[root]=To;
 51             maxn=size[To];
 52         }
 53     }
 54     return 0;
 55 }
 56 int dfs2(int F,int root,int Top){
 57     top[root]=Top;
 58     new_id[root]=++cnt;
 59     old_id[cnt]=root;
 60     if(heavy_son[root]) dfs2(root,heavy_son[root],Top);
 61     for(int i=last[root];i;i=line[i].next){
 62         int To=line[i].to;
 63         if(F==To||heavy_son[root]==To) continue;
 64         dfs2(root,To,To);
 65     }
 66 }
 67 int build(int x,int l,int r){
 68     if(l==r){
 69         tree[x]=v[old_id[l]]%Mod;
 70         return 0;
 71     }
 72     int mid=(l+r)/2;
 73     build(x*2,l,mid);
 74     build(x*2+1,mid+1,r);
 75     tree[x]=(tree[x*2]+tree[x*2+1])%Mod;
 76 }
 77 int deal_lazy(int deal_fh,int deal_l,int deal_r,int deal_v){
 78     lazy[deal_fh]=(lazy[deal_fh]+deal_v)%Mod;
 79     tree[deal_fh]=(tree[deal_fh]+((deal_r-deal_l+1)*deal_v%Mod))%Mod;
 80 }
 81 int push_down1(int fh,int ll,int rr){
 82     int mid=(ll+rr)/2;
 83     deal_lazy(fh*2,ll,mid,lazy[fh]);
 84     deal_lazy(fh*2+1,mid+1,rr,lazy[fh]);
 85     lazy[fh]=0;
 86 }
 87 int total(int x,int l,int r,int b_l,int b_r){
 88     if(b_l<=l&&r<=b_r) return tree[x];
 89     push_down1(x,l,r);
 90     int mid=(l+r)/2,ans=0;
 91     if(b_l<=mid) ans=(ans+total(x*2,l,mid,b_l,b_r))%Mod;
 92     if(mid+1<=b_r) ans=(ans+total(x*2+1,mid+1,r,b_l,b_r))%Mod;
 93     return ans;
 94 }
 95 int turn(int x,int l,int r,int b_l,int b_r,int v){
 96     if(b_l<=l&&r<=b_r){
 97         tree[x]=(tree[x]+((r-l+1)*v%Mod))%Mod;
 98         lazy[x]=(lazy[x]+v)%Mod;
 99         return 0;
100     }
101     push_down1(x,l,r);
102     int mid=(l+r)/2;
103     if(b_l<=mid) turn(x*2,l,mid,b_l,b_r,v);
104     if(mid+1<=b_r) turn(x*2+1,mid+1,r,b_l,b_r,v);
105     tree[x]=(tree[x*2]+tree[x*2+1])%Mod;
106     return 0;
107 }
108 int course_1(int x,int y,int z){
109     while(top[x]!=top[y]){
110         if(dep[top[x]]>=dep[top[y]]){
111             turn(1,1,n,new_id[top[x]],new_id[x],z);
112             x=dad[top[x]];
113         }
114         else{
115             turn(1,1,n,new_id[top[y]],new_id[y],z);
116             y=dad[top[y]];
117         }
118     }
119     if(dep[x]<=dep[y]) turn(1,1,n,new_id[x],new_id[y],z);
120     else turn(1,1,n,new_id[y],new_id[x],z);
121     return 0;
122         
123 }
124 int course_2(int x,int y){
125     int ans=0;
126     while(top[x]!=top[y]){
127         if(dep[top[x]]>=dep[top[y]]){
128             ans=(ans+total(1,1,n,new_id[top[x]],new_id[x]))%Mod;
129             x=dad[top[x]];
130         }
131         else{
132             ans=(ans+total(1,1,n,new_id[top[y]],new_id[y]))%Mod;    
133             y=dad[top[y]];
134         }
135     }
136     if(dep[x]<=dep[y]) ans=(ans+total(1,1,n,new_id[x],new_id[y]))%Mod;
137     else ans=(ans+total(1,1,n,new_id[y],new_id[x]))%Mod;
138     return ans;
139         
140 }
141 int main(){
142     scanf("%d%d%d%d",&n,&m,&s,&Mod);
143     for(int i=1;i<=n;i++) scanf("%d",&v[i]);
144     for(int i=1;i<=n-1;i++){
145         int UU,VV;
146         scanf("%d%d",&UU,&VV);
147         add(UU,VV);
148         add(VV,UU);
149     }
150     dfs1(s,s,1);
151     dfs2(s,s,s);
152     build(1,1,n);
153     while(m--){
154         int xh;
155         scanf("%d",&xh);
156         if(xh==1){
157             int X,Y,Z;
158             scanf("%d%d%d",&X,&Y,&Z);
159             course_1(X,Y,Z);
160             continue;
161         }
162         if(xh==2){
163             int X,Y;
164             scanf("%d%d",&X,&Y);
165             printf("%d\n",course_2(X,Y));
166             continue;
167         }
168         if(xh==3){
169             int R,VAL;
170             scanf("%d%d",&R,&VAL);
171             turn(1,1,n,new_id[R],new_id[R]+size[R]-1,VAL%Mod);
172             continue;
173         }
174         int R;
175         scanf("%d",&R);
176         printf("%d\n",total(1,1,n,new_id[R],new_id[R]+size[R]-1));
177     }
178 }

 

posted @ 2020-10-27 20:38  latent_Lin  阅读(82)  评论(0)    收藏  举报