如题,已知一棵包含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哟!