bzoj3730:震波


題意:給一棵樹,只有點權無邊權, ,每次詢問求以一個點為中心,半徑為k的全職和。

考慮動態樹分治。我們對於每個點(點分樹)維護兩個樹狀數組。兩個樹狀數組都以距離為下標,權值為內容。第一個樹狀數組維護子樹中距離該點為k的權值和,第二個維護距離該點父親距離為k的權值和。這樣改權值時我們暴力爬樹高,loglog復雜度(log的樹高加上log的樹狀數組)。查詢的時候一樣爬樹高,要注意容斥(把當前子樹k的先加起來,往祖先上爬,如果距離小於k,假設為d,我們到祖先上去求一個k-d,再容斥掉原來這棵子樹里被計算過的,這就是第二個樹狀數組的用處)。

時間復雜度0(nloglog),空間復雜度O(nlog)(如果用線段樹還要加一個log。這里BB一句,為什么樹狀數組不會爆呢,因為你每一層開的大小為子樹大小的話,每層總和n,總共log層,空間就是nlog的。其實就跟點分治的時間復雜度證明一樣。用vector來開並且加上函數resize()就可以辦到了。)

這道題花了整整一天才寫出來。。。一直RE(實際是WA,畢竟防離線加密,如果答案錯了后面輸入都是錯的),總結一下錯誤:

1.想的只用一個樹狀數組維護,實際上為了容斥必須要用上第二個樹狀數組。

2.更新時,一開始要把自己丟在自己的第二個樹狀數組里面

3.2這玩意肯定要寫在爬樹循環外面啊(你是SB嗎)

4.應該用qsum而不是query去爬樹高(一開始腦袋抽了。。)

5.往樹上爬的時候是不會中途退出的,不會因為有一個祖先爬不上去就終止,說不定有一個爺爺就在你旁邊你可以過去呢。

對於點分樹的題就想象成爬山吧,我們用每一層的重心將點們分割開來,每次爬樹高都是解鎖區域,翻過一座高山。

還有,點分樹自己腦補的板子實在太丑陋了。。這里膜拜一下ihopenot大佬,板子神快,我一開始好不容易調出來T了,參考了一下大佬的板子后就rank8了,真乃神人也!

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define INF 1e9
 5 #define lowbit(i) ((i)&-(i))
 6 int n,m,head[N],val[N],fa[N][20],dis[N][20],s[N],f[N],dep[N],rt,sz,cnt,ans;
 7 bool vis[N];
 8 vector<int>bit[N],fbit[N];
 9 inline int read(){
10     int x=0,f=1; char a=getchar();
11     while(a>'9' || a<'0') {if(a=='-') f=-1; a=getchar();}
12     while(a<='9' && a>='0') x=x*10+a-'0',a=getchar();
13     return x*f;
14 } 
15 struct edges{
16     int to,next;
17 }e[2*N];
18 inline void insert(){
19     int u=read(),v=read();
20     e[cnt]=(edges){v,head[u]};head[u]=cnt++;
21     e[cnt]=(edges){u,head[v]};head[v]=cnt++;
22 }
23 void getroot(int x,int father){
24     s[x]=1; f[x]=0;
25     for(int i=head[x];i>=0;i=e[i].next){
26         if(vis[e[i].to] || father==e[i].to) continue;
27         getroot(e[i].to,x); s[x]+=s[e[i].to];
28         f[x]=max(f[x],s[e[i].to]);
29     }
30     f[x]=max(f[x],sz-s[x]);
31     if(f[x]<f[rt]) rt=x;
32 }
33 void getship(int x,int anc,int father,int d){
34     for(int i=head[x];i>=0;i=e[i].next){
35      int v=e[i].to;
36      if(!vis[v] && v!=father) fa[v][++dep[v]]=anc,dis[v][dep[v]]=d,getship(v,anc,x,d+1);
37     }
38 }
39 void Buildtree(int x){
40     vis[x]=1; getship(x,x,0,1); 
41     int all=sz; bit[x].resize(all+1); fbit[x].resize(all+1);
42     for(int i=head[x];i>=0;i=e[i].next){
43         if(vis[e[i].to]) continue;
44         sz=s[e[i].to]; if(sz>s[x]) sz=all-s[x];
45         rt=0; getroot(e[i].to,x); Buildtree(rt);
46     }
47 }
48 inline int qsum(int x,int k){
49     int ret=val[x],lim=bit[x].size()-1; k=min(k,lim); 
50     for(int i=k;i;i-=lowbit(i)) ret+=bit[x][i];
51     return ret;
52 }
53 inline int qsum2(int x,int k){
54     int ret=0,lim=fbit[x].size()-1; k=min(k,lim);
55     for(int i=k;i;i-=lowbit(i)) ret+=fbit[x][i];
56     return ret;
57 }
58 inline void change(int x,int v){
59     int d,lim; 
60     d=dis[x][dep[x]]; lim=bit[x].size()-1;
61     for(int j=d;j<=lim && j;j+=lowbit(j)) fbit[x][j]+=v;
62     for(int i=dep[x];i;i--){
63         d=dis[x][i]; lim=bit[fa[x][i]].size()-1;
64         for(int j=d;j<=lim;j+=lowbit(j)) bit[fa[x][i]][j]+=v;
65         d=dis[x][i-1];
66         for(int j=d;j<=lim && j;j+=lowbit(j)) fbit[fa[x][i]][j]+=v;
67     }
68 }
69 int query(int x,int k){
70     int ret=qsum(x,k);
71     for(int i=dep[x];i;i--) if(dis[x][i]<=k)
72     ret+=qsum(fa[x][i],k-dis[x][i])-qsum2(fa[x][i+1],k-dis[x][i]);
73     return ret;
74 }
75 int main(){
76     n=read(); m=read(); memset(head,-1,sizeof(head));
77     for(int i=1;i<=n;i++) val[i]=read();
78     for(int i=1;i<n;i++) insert();
79     f[0]=INF; sz=n; getroot(1,0); Buildtree(rt); 
80     for(int i=1;i<=n;i++) fa[i][dep[i]+1]=i;
81     for(int i=1;i<=n;i++) change(i,val[i]);
82     while(m--){
83         int a=read(),b=read()^ans,c=read()^ans;
84         if(!a) ans=query(b,c),printf("%d\n",ans);
85         else change(b,c-val[b]),val[b]=c;
86     }
87     return 0;
88 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM