[bzoj4765]普通計算姬(分塊+樹狀數組+DFS序)
阿新 • • 發佈:2018-08-16
-- 位置 print names ont div 修改 turn nlog
題意
給定一棵n個節點的帶權樹,節點編號為1到n,以root為根,設sum[p]表示以點p為根的這棵子樹中所有節點的權值和。
計算姬支持下列兩種操作: 1 給定兩個整數u,v,修改點u的權值為v。 2 給定兩個整數l,r,計算sum[l]+sum[l+1]+….+sum[r-1]+sum[r]
N<=10^5,M<=10^5
題解
每一個塊中統計sum[i]的和,這個直接求出DFS序維護樹狀數組nlogn統計就行。
然後詢問時對於一個整塊直接加上我們統計的sum[i]的和,然後對於邊角余料,我們用樹狀數組求就行。
修改時我們要維護樹狀數組直接位置上加(x-v[i])就行。
然後我們要維護塊的和,就需要把和加上塊中i的祖先數(包含i)*(x-v[i])。
所以我們預處理出f[i][j]代表第i塊中j(包括j)的祖先數。這個dfs中用一個數組記錄祖先情況(進入時加上自己,推出時減掉自己),對於每個點掃一遍每個塊統計就行。
然後這題要用unsigned long long 然後也不能全開,會MLE
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const intN=100100; 8 int cnt,head[N]; 9 int size[N],id[N],tot; 10 int num[400],block[N],f[400][N]; 11 unsigned long long sum[400],a[N],tr[N],ans,v[N]; 12 int n,m,R[400],L[400],Block,root; 13 struct edge{ 14 int to,nxt; 15 }e[N*2]; 16 void add(int u,int v){ 17 cnt++; 18 e[cnt].nxt=head[u];19 e[cnt].to=v; 20 head[u]=cnt; 21 } 22 void dfs1(int u,int fa){ 23 size[u]=1; 24 id[u]=++tot; 25 for(int i=head[u];i;i=e[i].nxt){ 26 int v=e[i].to; 27 if(v==fa)continue; 28 dfs1(v,u); 29 size[u]+=size[v]; 30 } 31 } 32 void dfs2(int u,int fa){ 33 num[block[u]]++; 34 for(int i=1;i<=block[n];i++){ 35 f[i][u]+=num[i]; 36 } 37 for(int i=head[u];i;i=e[i].nxt){ 38 int v=e[i].to; 39 if(v==fa)continue; 40 dfs2(v,u); 41 } 42 num[block[u]]--; 43 } 44 int lowbit(int x){ 45 return x&-x; 46 } 47 void update(int x,unsigned long long w){ 48 for(int i=x;i<=n;i+=lowbit(i)){ 49 tr[i]+=w; 50 } 51 } 52 unsigned long long query(int x){ 53 unsigned long long tmp=0; 54 for(int i=x;i;i-=lowbit(i)){ 55 tmp+=tr[i]; 56 } 57 return tmp; 58 } 59 int main(){ 60 scanf("%d%d",&n,&m); 61 for(int i=1;i<=n;i++){ 62 scanf("%llu",&v[i]); 63 } 64 for(int i=1;i<=n;i++){ 65 int u,v; 66 scanf("%d%d",&u,&v); 67 if(u==0){ 68 root=v; 69 continue; 70 } 71 add(u,v); 72 add(v,u); 73 } 74 dfs1(root,0); 75 for(int i=1;i<=n;i++){ 76 update(id[i],v[i]); 77 } 78 for(int i=1;i<=n;i++){ 79 a[i]=query(id[i]+size[i]-1)-query(id[i]-1); 80 // cout<<i<<" "<<id[i]<<" "<<size[i]<<" "<<a[i]<<endl; 81 } 82 Block=sqrt(n); 83 for(int i=1;i<=n;i++){ 84 block[i]=(i-1)/Block+1; 85 sum[block[i]]+=a[i]; 86 if(!L[block[i]])L[block[i]]=i; 87 R[block[i]]=i; 88 } 89 dfs2(root,0); 90 while(m--){ 91 int k,x,y; 92 scanf("%d%d%d",&k,&x,&y); 93 if(k==1){ 94 for(int i=1;i<=block[n];i++){ 95 sum[i]+=f[i][x]*(y-v[x]); 96 } 97 update(id[x],y-v[x]); 98 v[x]=y; 99 } 100 else{ 101 ans=0; 102 if(block[x]+1>=block[y]){ 103 for(int i=x;i<=y;i++){ 104 ans+=query(id[i]+size[i]-1)-query(id[i]-1); 105 } 106 } 107 else{ 108 for(int i=block[x]+1;i<=block[y]-1;i++){ 109 ans+=sum[i]; 110 } 111 for(int i=x;i<=R[block[x]];i++){ 112 ans+=query(id[i]+size[i]-1)-query(id[i]-1); 113 } 114 for(int i=L[block[y]];i<=y;i++){ 115 ans+=query(id[i]+size[i]-1)-query(id[i]-1); 116 } 117 } 118 printf("%llu\n",ans); 119 } 120 } 121 return 0; 122 }
[bzoj4765]普通計算姬(分塊+樹狀數組+DFS序)