洛谷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取模)
输入输出样例
说明
时空限制:1s,128M
数据规模:
对于30%的数据: N≤10,M≤10
对于70%的数据: N≤10^3,M≤10^3
对于100%的数据: N≤10^5,M≤10^5
( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )
样例说明:
树的结构如下:
各个操作如下:
故输出应依次为2、21(重要的事情说三遍:记得取模)
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #define maxn 100007 7 using namespace std; 8 long long read() 9 { 10 long long x=0,f=1; 11 char ch=getchar(); 12 while(ch<'0'||ch>'9') 13 { 14 if(ch=='-') 15 f=-1; 16 ch=getchar(); 17 } 18 while(ch>='0'&&ch<='9') 19 { 20 x=x*10+ch-'0'; 21 ch=getchar(); 22 } 23 return x*f; 24 } 25 int n,m,num,root,p,opt,x,y,z,cnt; 26 int head[maxn*2],a[maxn],son[maxn],fa[maxn],deep[maxn],size[maxn],top[maxn],pos[maxn],data[maxn],in[maxn],out[maxn]; 27 struct node 28 { 29 int v,nxt; 30 } e[maxn]; 31 void add(int u,int v) 32 { 33 e[++num].v=v; 34 e[num].nxt=head[u]; 35 head[u]=num; 36 e[++num].v=u; 37 e[num].nxt=head[v]; 38 head[v]=num; 39 } 40 struct NODE 41 { 42 int l,r,sum,flag; 43 } tree[maxn*4]; 44 void dfs(int now) 45 { 46 size[now]=1; 47 for(int i=head[now]; i; i=e[i].nxt) 48 if(fa[now]!=e[i].v) 49 { 50 fa[e[i].v]=now; 51 deep[e[i].v]=deep[now] + 1; 52 dfs(e[i].v); 53 size[now]+=size[e[i].v]; 54 if(size[son[now]]<size[e[i].v]) 55 son[now]=e[i].v; 56 } 57 } 58 void DFS(int now,int num) 59 { 60 top[now]=num; 61 pos[now]=++cnt; 62 in[now]=cnt; 63 data[cnt]=a[now]; 64 if(son[now]) 65 DFS(son[now],num); 66 for(int i=head[now]; i; i=e[i].nxt) 67 if(fa[now]!=e[i].v&&e[i].v!=son[now]) 68 DFS(e[i].v,e[i].v); 69 out[now]=cnt; 70 } 71 void build(int now,int l,int r) 72 { 73 tree[now].l=l; 74 tree[now].r=r; 75 tree[now].flag=0; 76 if(l==r) 77 { 78 tree[now].sum=data[l]; 79 return ; 80 } 81 int mid=(l+r)>>1; 82 build(now<<1,l,mid); 83 build(now<<1|1,mid+1,r); 84 tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum; 85 } 86 void down(int now) 87 { 88 if(tree[now].l==tree[now].r) 89 { 90 tree[now].flag=0; 91 return ; 92 } 93 tree[now<<1].flag+=tree[now].flag; 94 tree[now<<1|1].flag+=tree[now].flag; 95 tree[now<<1].sum=(tree[now<<1].sum+tree[now].flag*(tree[now<<1].r-tree[now<<1].l+1))%p; 96 tree[now<<1|1].sum=(tree[now<<1|1].sum+tree[now].flag*(tree[now<<1|1].r-tree[now<<1|1].l+1))%p; 97 tree[now].flag=0; 98 } 99 void change(int now,int l,int r,int f) 100 { 101 while(tree[now].flag) 102 down(now); 103 if(tree[now].l>r||tree[now].r<l) 104 return ; 105 if(tree[now].l>=l&&tree[now].r<=r) 106 { 107 tree[now].flag=f; 108 (tree[now].sum+=f*(tree[now].r-tree[now].l+1))%=p; 109 return ; 110 } 111 change(now<<1,l,r,f); 112 change(now<<1|1,l,r,f); 113 tree[now].sum=(tree[now<<1].sum+tree[now<<1|1].sum)%p; 114 } 115 int query(int now,int l,int r) 116 { 117 while(tree[now].flag) down(now); 118 if(tree[now].l>r||tree[now].r<l) 119 return 0; 120 if(tree[now].l>=l&&tree[now].r<=r) 121 return tree[now].sum; 122 return (query(now<<1,l,r)+query(now<<1|1,l,r))%p; 123 } 124 void add1() 125 { 126 x=read(),y=read(),z=read(),z%=p; 127 while(top[x]!=top[y]) 128 { 129 if(deep[top[x]]<deep[top[y]]) 130 swap(x,y); 131 change(1,pos[top[x]],pos[x],z); 132 x=fa[top[x]]; 133 } 134 if(deep[x]<deep[y]) 135 swap(x,y); 136 change(1,pos[y],pos[x],z); 137 } 138 void add2() 139 { 140 x=read(),z=read(),z%=p; 141 change(1,in[x],out[x],z); 142 } 143 void query1() 144 { 145 x=read(),y=read(); 146 int ans=0; 147 while(top[x]!=top[y]) 148 { 149 if(deep[top[x]]<deep[top[y]]) 150 swap(x,y); 151 ans=(ans+query(1,pos[top[x]],pos[x]))%p; 152 x=fa[top[x]]; 153 } 154 if(deep[x]<deep[y]) 155 swap(x,y); 156 (ans+=query(1,pos[y],pos[x]))%=p; 157 printf("%d\n",ans); 158 } 159 void query2() 160 { 161 x=read(); 162 int ans=0; 163 (ans=query(1,in[x],out[x]))%=p; 164 printf("%d\n",ans); 165 } 166 int main() 167 { 168 n=read(),m=read(),root=read(),p=read(); 169 for(int i=1; i<=n; ++i) 170 a[i]=read(),a[i]%=p; 171 for(int i=1,a,b; i<n; ++i) 172 a=read(),b=read(),add(a,b); 173 dfs(root); 174 DFS(root,root); 175 build(1,1,n); 176 while(m--) 177 { 178 opt=read(); 179 if(opt==1) 180 add1(); 181 else if(opt==3) 182 add2(); 183 else if(opt==2) 184 query1(); 185 else 186 query2(); 187 } 188 return 0; 189 }