洛谷 P3384 【模板】树链剖分 如题
- 时空限制1s / 128MB
题目描述
如题,已知一棵包含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 \leq 10, M \leq 10N≤10,M≤10
对于70%的数据: N \leq {10}^3, M \leq {10}^3N≤103,M≤103
对于100%的数据: N \leq {10}^5, M \leq {10}^5N≤105,M≤105
( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )
样例说明:
树的结构如下:
各个操作如下:
故输出应依次为2、21(重要的事情说三遍:记得取模)
-------------------------------------------------------------------------------------------------------------
树链剖分就是把在原树上的操作转化为在线段树上操作
对于操作一、三,我们把它变成区间加;
对于操作二、四,变成区间求和。
特别的,对于操作三、四
因为原树上的点的映射pos(其实就是给原树结点重新编号)有着连续性:
一个结点的父节点一定小于这个结点,且是连续的
所以一颗子树中所有的点都比根节点大,且是连续的
所以可以放到线段树上操作
比如映射点pos[x]的子树,在线段树上的区间为pos[x]到pos[x]+size[x]-1 //size[x]表示以x为根节点的子树拥有的结点总数
感觉比 这题 要难?
存板子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #define maxn 233333 5 using namespace std; 6 struct node{int to,next;}; 7 struct rode{int l,r,sum,tag;}; 8 node e[maxn<<1]; 9 rode tr[maxn<<2]; 10 int read(); 11 int n,m,r,p,pre[maxn],cnt,v[maxn],fa[maxn],dep[maxn],size[maxn],poi,pos[maxn],bl[maxn]; 12 int solvelsum(int,int); 13 void ladd(int,int,int); 14 void add(int,int,int,int); 15 int querysum(int,int,int); 16 void pushdown(int); 17 void pushup(int); 18 void change(int,int,int); 19 void build(int,int,int); 20 void dfs1(int); 21 void dfs2(int,int); 22 void ins(int,int); 23 int main(){ 24 n=read();m=read();r=read();p=read(); 25 for(int i=1;i<=n;i++) v[i]=read(); 26 cnt=0;poi=0; 27 for(int i=1;i<n;i++){ 28 int x=read(),y=read(); 29 ins(x,y); 30 } 31 fa[r]=r;dep[r]=1; 32 dfs1(r); 33 dfs2(r,r); 34 build(1,n,1); 35 for(int i=1;i<=n;i++) change(pos[i],v[i],1); 36 for(int i=1;i<=m;i++){ 37 int o=read(); 38 if(o==1){ 39 int x=read(),y=read(),z=read(); 40 ladd(x,y,z); 41 } 42 else if(o==2){ 43 int x=read(),y=read(); 44 printf("%d\n",solvelsum(x,y)); 45 } 46 else if(o==3){ 47 int x=read(),y=read(); 48 add(pos[x],pos[x]+size[x]-1,y,1); 49 } 50 else{ 51 int x=read(); 52 printf("%d\n",querysum(pos[x],pos[x]+size[x]-1,1)); 53 } 54 } 55 return 0; 56 } 57 #define lson ro<<1 58 #define rson ro<<1|1 59 int solvelsum(int x,int y){ 60 int sum=0; 61 while(bl[x]!=bl[y]){ 62 if(dep[bl[x]]<dep[bl[y]]) swap(x,y); 63 sum=(sum+querysum(pos[bl[x]],pos[x],1))%p; 64 x=fa[bl[x]]; 65 } 66 if(pos[x]>pos[y]) swap(x,y); 67 sum=(sum+querysum(pos[x],pos[y],1))%p; 68 return sum; 69 } 70 void ladd(int x,int y,int k){ 71 while(bl[x]!=bl[y]){ 72 if(dep[bl[x]]<dep[bl[y]]) swap(x,y); 73 add(pos[bl[x]],pos[x],k,1); 74 x=fa[bl[x]]; 75 } 76 if(pos[x]>pos[y]) swap(x,y); 77 add(pos[x],pos[y],k,1); 78 } 79 void add(int l,int r,int k,int ro){ 80 if(l<=tr[ro].l&&tr[ro].r<=r){ 81 tr[ro].sum=(tr[ro].sum+(tr[ro].r-tr[ro].l+1)*k)%p; 82 tr[ro].tag=(tr[ro].tag+k)%p; 83 return; 84 } 85 if(tr[ro].tag) pushdown(ro); 86 int mid=(tr[ro].l+tr[ro].r)>>1; 87 if(l<=mid) add(l,r,k,lson); 88 if(r>mid) add(l,r,k,rson); 89 pushup(ro); 90 } 91 int querysum(int l,int r,int ro){ 92 if(l<=tr[ro].l&&tr[ro].r<=r) return tr[ro].sum; 93 if(tr[ro].tag) pushdown(ro); 94 int mid=(tr[ro].l+tr[ro].r)>>1; 95 if(l<=mid&&mid<r) return (querysum(l,r,lson)+querysum(l,r,rson))%p; 96 if(l<=mid) return querysum(l,r,lson); 97 if(r>mid) return querysum(l,r,rson); 98 } 99 void pushdown(int ro){ 100 int k=tr[ro].tag;tr[ro].tag=0; 101 tr[lson].tag=(tr[lson].tag+k)%p; 102 tr[rson].tag=(tr[rson].tag+k)%p; 103 tr[lson].sum=(tr[lson].sum+(tr[lson].r-tr[lson].l+1)*k)%p; 104 tr[rson].sum=(tr[rson].sum+(tr[rson].r-tr[rson].l+1)*k)%p; 105 } 106 void pushup(int ro){ 107 tr[ro].sum=(tr[lson].sum+tr[rson].sum)%p; 108 } 109 void change(int x,int k,int ro){ 110 if(tr[ro].l==tr[ro].r){ 111 tr[ro].sum=k%p; 112 return; 113 } 114 int mid=(tr[ro].l+tr[ro].r)>>1; 115 if(x<=mid) change(x,k,lson); 116 else change(x,k,rson); 117 pushup(ro); 118 } 119 void build(int l,int r,int ro){ 120 tr[ro].l=l;tr[ro].r=r; 121 if(l==r) return; 122 int mid=(l+r)>>1; 123 build(l,mid,lson); 124 build(mid+1,r,rson); 125 } 126 void dfs2(int x,int chain){ 127 int k=0; 128 pos[x]=++poi; 129 bl[x]=chain; 130 for(int i=pre[x];i;i=e[i].next){ 131 int to=e[i].to; 132 if(dep[to]>dep[x]&&size[to]>size[k]) k=to; 133 } 134 if(k==0) return; 135 dfs2(k,chain); 136 for(int i=pre[x];i;i=e[i].next){ 137 int to=e[i].to; 138 if(dep[to]>dep[x]&&k!=to) dfs2(to,to); 139 } 140 } 141 void dfs1(int x){ 142 size[x]=1; 143 for(int i=pre[x];i;i=e[i].next){ 144 int to=e[i].to; 145 if(fa[x]!=to){ 146 fa[to]=x; 147 dep[to]=dep[x]+1; 148 dfs1(to); 149 size[x]+=size[to]; 150 } 151 } 152 } 153 void ins(int x,int y){ 154 e[++cnt].to=y;e[cnt].next=pre[x];pre[x]=cnt; 155 e[++cnt].to=x;e[cnt].next=pre[y];pre[y]=cnt; 156 } 157 int read(){ 158 int ans=0,f=1;char c=getchar(); 159 while('0'>c||c>'9'){if(c=='-')f=-1;c=getchar();} 160 while('0'<=c&&c<='9')ans=ans*10+c-48,c=getchar();return ans*f; 161 }