普通计算姬
题意:
给出$n$个点的树,记$sum(x)$为$x$子树的点权和。$m$此操作
1.将一个点的权值改为c
2.查询$\sum_{x=l}^r { sum(x)}$
解法:
修改一个点 x 的点权会使得从x到root的所有点的$sum(i)$加上一个数字。
考虑对1~n分块,块的大小为$O(\sqrt {\frac{n}{logn}})$。
对于每个块i,计算出$cnt(i,x)$表示如果在x点加上v则$ans(i) = \sum_{j=left}^{right}{sum(j)}$
会加上$cnt(i,x)*v$,这个可以应用dfs序+差分树状数组求出。
对于每组查询,树状数组暴力小块,中间块直接加上$ans(i)$,$O(\sqrt {nlogn})$
对于修改,应用$cnt$实现$O(\sqrt {nlogn})$修改。
注意根据内存限制调整一下块的大小,注意答案炸long long(并不想手写__int128,cpp经本地对拍)。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <cstdlib> 6 7 #define LL long long 8 #define N 100010 9 #define SIZ 320 10 #define p E[i].x 11 #define lbt(x) (x&(-x)) 12 #define MOD 1000000000000000000LL 13 14 using namespace std; 15 16 struct edge 17 { 18 int x,to; 19 }E[N<<1]; 20 21 LL ansv[SIZ]; 22 int n,m,tott,totb,totE,root,SIZE; 23 int g[N],belong[N],L[N],R[N]; 24 int cntv[SIZ][N]; 25 LL d[N]; 26 __int128 sumv[N],ans[N]; 27 28 void addedge(int x,int y) 29 { 30 E[++totE] = (edge){y,g[x]}; g[x]=totE; 31 E[++totE] = (edge){x,g[y]}; g[y]=totE; 32 } 33 34 __int128 ask(int x) 35 { 36 __int128 ans; 37 for(int i=x;i>0;i-=lbt(i)) 38 ans = ans + sumv[i]; 39 return ans; 40 } 41 42 void add(int x,LL v) 43 { 44 for(int i=x;i<=n && i;i+=lbt(i)) 45 sumv[i] += v; 46 } 47 48 void dfs(int x,int fa) 49 { 50 L[x] = ++tott; 51 for(int i=g[x];i;i=E[i].to) 52 if(p!=fa) dfs(p,x); 53 R[x]=tott; 54 } 55 56 void com_add(int x,LL v) 57 { 58 d[x]+=v; 59 add(L[x],(LL)v); 60 for(int t=1;t<=totb;t++) 61 ans[t] += (cntv[t][x]*(LL)v); 62 } 63 64 __int128 com_ask(int l,int r) 65 { 66 __int128 ansv; 67 int lb=belong[l],rb=belong[r]; 68 if(lb==rb) 69 { 70 for(int i=l;i<=r;i++) 71 ansv+=ask(R[i])-ask(L[i]-1); 72 return ansv; 73 } 74 for(int i=l;i<=lb*SIZE;i++) 75 ansv += ask(R[i])-ask(L[i]-1); 76 for(int i=lb+1;i<rb;i++) ansv += ans[i]; 77 for(int i=(rb-1)*SIZE+1;i<=r;i++) 78 ansv += ask(R[i])-ask(L[i]-1); 79 return ansv; 80 } 81 82 int main() 83 { 84 ios::sync_with_stdio(false); 85 scanf("%d%d",&n,&m); 86 SIZE=(int)sqrt(n+0.5); 87 for(int i=1;i<=n;i++) scanf("%lld",&d[i]); 88 for(int i=1,x,y;i<=n;i++) 89 { 90 scanf("%d%d",&x,&y); 91 if(!x) root=y; 92 else addedge(x,y); 93 } 94 tott=0; 95 dfs(root,root); 96 for(int i=1;i<=n;i++) belong[i] = (i-1)/SIZE+1; 97 totb=belong[n]; 98 for(int t=1;t<=totb;t++) 99 { 100 for(int i=(t-1)*SIZE+1;i<=min(t*SIZE,n);i++) 101 { 102 add(L[i],1); 103 add(R[i]+1,-1); 104 } 105 for(int i=1;i<=n;i++) 106 cntv[t][i]=(int)ask(L[i]).b; 107 for(int i=(t-1)*SIZE+1;i<=min(t*SIZE,n);i++) 108 { 109 add(L[i],-1); 110 add(R[i]+1,1); 111 } 112 } 113 for(int i=1;i<=n;i++) add(L[i],d[i]); 114 for(int i=1;i<=totb;i++) ans[i].a=ans[i].b=0; 115 for(int i=1;i<=n;i++) 116 ans[belong[i]] += ask(R[i])-ask(L[i]-1); 117 for(int i=1,cmd,x;i<=m;i++) 118 { 119 LL v; 120 scanf("%d%d%lld",&cmd,&x,&v); 121 if(cmd==1) com_add(x,v-d[x]); 122 else cout << com_ask(x,v) << endl; 123 } 124 return 0; 125 } 126 /* 127 6 4 128 0 0 3 4 0 1 129 0 1 130 1 2 131 2 3 132 2 4 133 3 5 134 5 6 135 2 1 2 136 1 1 1 137 2 3 6 138 2 3 5 139 */