[luogu 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为根节点的子树内所有节点值之和

输入输出格式

输入格式:

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

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

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

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

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

输出格式:

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

输入输出样例

输入样例#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

说明

时空限制:1s,128M

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=1000,M<=1000

对于100%的数据:N<=100000,M<=100000

(其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233)

样例说明:

树的结构如下:

各个操作如下:

故输出应依次为2、21(重要的事情说三遍:记得取模)


My Solution

哪来的什么solution

因为这题快颓了week了

统计:2/29   AC!!!

为什么我之前要用树状数组嘞

向unsigned大佬低头    orz

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 using namespace std;
  5 
  6 typedef long long ll;
  7 
  8 inline int read(){
  9     char ch;
 10     int re=0;
 11     bool flag=0;
 12     while((ch=getchar())!='-'&&(ch<'0'||ch>'9'));
 13     ch=='-'?flag=1:re=ch-'0';
 14     while((ch=getchar())>='0'&&ch<='9')  re=re*10+ch-'0';
 15     return flag?-re:re;
 16 }
 17 
 18 inline ll rea(){
 19     char ch;
 20     ll re=0;
 21     bool flag=0;
 22     while((ch=getchar())!='-'&&(ch<'0'||ch>'9'));
 23     ch=='-'?flag=1:re=ch-'0';
 24     while((ch=getchar())>='0'&&ch<='9')  re=re*10+ch-'0';
 25     return flag?-re:re;
 26 }
 27 
 28 struct edge{
 29     int to,next;
 30     edge(int to=0,int next=0):
 31         to(to),next(next){}
 32 };
 33 
 34 struct Segment_Tree{
 35     int l,r;
 36     ll sum,tag; 
 37 };
 38 
 39 const int maxn=100001;
 40 
 41 int cnt,n,m,root;
 42 ll mod;
 43 edge edges[maxn<<1];
 44 Segment_Tree tre[maxn<<2];
 45 int head[maxn],top[maxn],dep[maxn],fat[maxn],id[maxn],id_[maxn],son[maxn],siz[maxn];
 46 int data[maxn];
 47 
 48 inline void add_edge(int from,int to){
 49     edges[++cnt]=edge(to,head[from]);  head[from]=cnt;
 50     edges[++cnt]=edge(from,head[to]);  head[to]=cnt;
 51 }
 52 
 53 void init(){
 54     n=read();  m=read();  root=read();  mod=rea();
 55     for(int i=1;i<=n;i++)
 56         data[i]=read();
 57     int from,to;
 58     cnt=0;
 59     for(int i=1;i<n;i++){
 60         from=read();  to=read();
 61         add_edge(from,to);
 62     }
 63 }
 64 
 65 void dfs_1(int x,int fa){
 66     fat[x]=fa;
 67     siz[x]=1;
 68     dep[x]=dep[fa]+1;
 69     for(int ee=head[x];ee;ee=edges[ee].next)
 70         if(edges[ee].to!=fa){
 71             dfs_1(edges[ee].to,x);
 72             siz[x]+=siz[edges[ee].to];
 73             if(!son[x]||siz[edges[ee].to]>siz[son[x]])
 74                 son[x]=edges[ee].to;
 75         }
 76 }
 77 
 78 void dfs_2(int x,int fa){
 79     if(!son[x])  return;
 80     top[son[x]]=top[x];
 81     id[son[x]]=++cnt;
 82     id_[cnt]=son[x];
 83     dfs_2(son[x],x);
 84     for(int ee=head[x];ee;ee=edges[ee].next)
 85         if(edges[ee].to!=fa&&edges[ee].to!=son[x]){
 86             top[edges[ee].to]=edges[ee].to;
 87             id[edges[ee].to]=++cnt;
 88             id_[cnt]=edges[ee].to;
 89             dfs_2(edges[ee].to,x);
 90         }
 91 }
 92 
 93 inline void push_up(int x){
 94     tre[x].sum=tre[x<<1].sum+tre[x<<1|1].sum;
 95 }
 96 
 97 inline void push_down(int x){
 98     tre[x<<1].tag+=tre[x].tag;
 99     tre[x<<1].sum+=tre[x].tag*(tre[x<<1].r-tre[x<<1].l+1);
100     tre[x<<1|1].tag+=tre[x].tag;
101     tre[x<<1|1].sum+=tre[x].tag*(tre[x<<1|1].r-tre[x<<1|1].l+1);
102     tre[x].tag=0;
103     return;
104 }
105 
106 void build(int x,int l,int r){
107     tre[x].l=l;  tre[x].r=r;
108     if(l==r){
109         tre[x].sum=data[id_[l]];
110         return;
111     }
112     int mid=(l+r)>>1;
113     build(x<<1,l,mid);
114     build(x<<1|1,mid+1,r);
115     push_up(x);
116 }
117 
118 void make(){
119     dfs_1(root,0);
120     cnt=1;
121     top[root]=root;
122     id[root]=cnt;
123     id_[cnt]=root;
124     dfs_2(root,0);
125     build(1,1,n);
126 }
127 
128 void update(int x,int L,int R,ll c){
129     if(L<=tre[x].l&&tre[x].r<=R){
130         tre[x].tag+=c;
131         tre[x].sum+=c*(tre[x].r-tre[x].l+1);
132         return;
133     }
134     push_down(x);
135     int mid=(tre[x].l+tre[x].r)>>1;
136     if(R<=mid)  update(x<<1,L,R,c);
137     else  if(L>mid)  update(x<<1|1,L,R,c);
138     else{
139         update(x<<1,L,mid,c);
140         update(x<<1|1,mid+1,R,c);
141     }
142     push_up(x);
143 }
144 
145 ll query_sum(int x,int L,int R){
146     if(L<=tre[x].l&&tre[x].r<=R)
147         return tre[x].sum;
148     push_down(x);
149     int mid=(tre[x].l+tre[x].r)>>1;
150     if(R<=mid)  return query_sum(x<<1,L,R);
151     else  if(L>mid)  return query_sum(x<<1|1,L,R);
152     else  return  query_sum(x<<1,L,mid)+query_sum(x<<1|1,mid+1,R);
153 }
154 
155 void change(int u,int v,ll c){
156     int f1=top[u];
157     int f2=top[v];
158     while(f1!=f2){
159         // this ensure u and v is not at the same heavy chain
160         if(dep[f1] < dep[f2]){
161             // ensure that heavy chain 1 is under heavy chain 2
162             swap(f1,f2);
163             swap(u,v);
164         }
165         update(1,id[f1],id[u],c);
166         u=fat[f1];
167         f1=top[u];
168     }
169     if(dep[u]>dep[v]) swap(u, v);
170     update(1,id[u],id[v],c);
171 }
172  
173 ll find_sum(int u, int v)
174 {
175     ll sum=0;
176     int f1=top[u];
177     int f2=top[v];
178     while(f1!=f2)
179     {
180         if(dep[f1]<dep[f2])
181         {
182             swap(f1,f2);
183             swap(u,v);
184         }
185         sum+=query_sum(1,id[f1],id[u]);
186         sum%=mod;
187         u=fat[f1];
188         f1=top[u];
189     }
190     if(dep[u]>dep[v])  swap(u, v);
191     sum+=query_sum(1,id[u],id[v]);
192     return sum%mod;
193 }
194 
195 void solve(){
196     int opt,ss,tt;
197     ll c;
198     for(int i=0;i<m;i++){
199         opt=read();
200         if(opt&1){
201             //opt==3
202             if(opt&2){
203                 ss=read();  c=rea();
204                 update(1,id[ss],id[ss]+siz[ss]-1,c);
205             }
206             //opt==1
207             else{
208                 ss=read();  tt=read();  c=rea();
209                 change(ss,tt,c);
210             }
211         } 
212         else{
213             //opt==4
214             if(opt&4){
215                 ss=read();
216                 printf("%lld
",query_sum(1,id[ss],id[ss]+siz[ss]-1)%mod);
217             }
218             //opt==2
219             else{
220                 ss=read();  tt=read();
221                 printf("%lld
",find_sum(ss,tt));
222             }
223         }
224     }
225 }
226 
227 int main(){
228     //freopen("data.in","r",stdin);
229     init();
230     make();
231     solve();
232     return 0;
233 }

爱你锋利的伤痕  爱你成熟的天真

原文地址:https://www.cnblogs.com/ZYBGMZL/p/6924413.html