动态点分治
[ZJOI2015]幻想乡战略游戏
给一棵树,边有边权,点有点权(初始为0),每次修改一个点的点权,并询问带权重心u使得所有点点权乘以到u的距离的和最小,输出这个最小值.
保证每个点度数不超过20
考虑对于一颗没有修改的树如何求带权重心
对于一条边(u,v),设u为v的父亲,sum[x]表示以x为根的子树的点权和,totsum表示整棵树的点权和.
从u到v,答案减小val(u,v)*sum[v],增加val(u,v)*totsum-sum[v]
那么v比u优当且仅当sum[v]>totsum-sum[v]即2*sum[v]>totsum
(等于的情况再往u的儿子移动sum只会变小,不可能变得更优了,所以直接把v作为答案即可)
所以从根出发一直往这样儿子走即可找到答案.当然这样复杂度会很高,,
这个时候就容易想到点分治了,因为若往分治儿子走最多只用走log次诶
每个点维护它管辖的所有点的点权和sum[x],对于每个点u,它管辖的区域内,和它的分治父亲v相连的点记为w
每次从根出发在分治树上找答案,当2*sum[u]>=tot时,从v走到u,同时将w到u的分治树上路径上的所有点的sum加上sum[v]-sum[u](找到答案回溯时要把sum还原)
这样就能在两个log内找到重心
知道点之后如何维护答案呢,再对每个点x维护g[x]表示它分治子树中所有点以它为根的答案和gtf[x]表示它分治子树中所有点以它分治父亲为根的答案
那么沿着分治父亲跳的时候,答案加上它父亲的g减去它的gtf加上它父亲的sum减去它的sum乘它到它父亲的距离
求距离时需要用到lca,最好用st表O(1)查询.lca都写挂的我..
1 // luogu-judger-enable-o2
2 //Achen
3 #include<algorithm>
4 #include<iostream>
5 #include<cstring>
6 #include<cstdlib>
7 #include<vector>
8 #include<cstdio>
9 #include<queue>
10 #include<cmath>
11 #include<set>
12 #define For(i,a,b) for(int i=(a);i<=(b);i++)
13 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
14 const int N=1e5+7;
15 typedef long long LL;
16 typedef double db;
17 using namespace std;
18 int n,Q,RT;
19
20 template<typename T> void read(T &x) {
21 char ch=getchar(); x=0; T f=1;
22 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
23 if(ch=='-') f=-1,ch=getchar();
24 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
25 }
26
27 int ecnt,fir[N],nxt[N<<1],to[N<<1],val[N<<1];
28 void add(int u,int v,int w) {
29 nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
30 nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
31 }
32
33 int dfs_clock,dfn[N],tid[N<<1],R[N],H[N];
34 void dfs(int x,int fa) {
35 dfn[x]=++dfs_clock;
36 tid[dfn[x]]=x;
37 R[x]=R[fa]+1;
38 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
39 H[to[i]]=H[x]+val[i];
40 dfs(to[i],x);
41 ++dfs_clock;
42 tid[dfs_clock]=x;
43 }
44 }
45
46 int st[N<<1][20];
47 void pre_RMQ() {
48 For(i,1,dfs_clock-1) st[i][0]=(R[tid[i]]<R[tid[i+1]])?tid[i]:tid[i+1];
49 For(j,1,17)
50 For(i,1,dfs_clock) if(i+(1<<j)<=dfs_clock)
51 st[i][j]=R[st[i][j-1]]<R[st[i+(1<<j-1)][j-1]]?st[i][j-1]:st[i+(1<<j-1)][j-1];
52 }
53
54 int lca(int x,int y) {
55 if(x==y) return x;
56 x=dfn[x]; y=dfn[y];
57 if(x>y) swap(x,y);
58 int k=0; while(x+(1<<k)<=y) k++; if(k) k--;
59 return R[st[x][k]]<R[st[y-(1<<k)][k]]?st[x][k]:st[y-(1<<k)][k];
60 }
61
62 int d[N];
63 LL f[N],g[N],gtf[N];//f:sum of d /g:ans /gtf:ans to f
64
65 int sz[N],mxson[N];
66 int rt,vis[N],F[N],sznow,wtf[N];
67 void dfs2(int x,int fa) {
68 sz[x]=1;
69 for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]&&to[i]!=fa) {
70 dfs2(to[i],x);
71 sz[x]+=sz[to[i]];
72 }
73 }
74
75 void get_rt(int x,int fa) {
76 sz[x]=mxson[x]=1;
77 for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]&&to[i]!=fa) {
78 get_rt(to[i],x);
79 sz[x]+=sz[to[i]];
80 mxson[x]=max(mxson[x],sz[to[i]]);
81 }
82 mxson[x]=max(mxson[x],sznow-sz[x]);
83 if(!rt||mxson[x]<mxson[rt]) rt=x;
84 }
85
86 int ec,fi[N],nx[N],tt[N];
87 void ADD(int u,int v) {
88 nx[++ec]=fi[u]; fi[u]=ec; tt[ec]=v;
89 }
90
91 void solve(int x,int FA) {
92 F[x]=FA;
93 if(FA) ADD(FA,x);
94 vis[x]=1;
95 dfs2(x,0);
96 for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) {
97 rt=0; sznow=sz[to[i]];
98 get_rt(to[i],x);
99 wtf[rt]=to[i]; solve(rt,x);
100 }
101 }
102
103 LL get_dis(int x,int y) { return H[x]+H[y]-2LL*H[lca(x,y)]; }
104
105 void change(int x,int y,int v) {
106 f[x]+=v;
107 g[x]+=(LL)v*get_dis(x,y);
108 gtf[x]+=(LL)v*get_dis(F[x],y);
109 if(F[x]) change(F[x],y,v);
110 }
111
112 int find(int x) {
113 for(int i=fi[x];i;i=nx[i]) {
114 int y=tt[i];
115 if(f[y]*2>f[x]) {
116 int z=wtf[y];
117 LL w=f[x]-f[y];
118 for(;;) {
119 f[z]+=w;
120 if(z==y) break;
121 z=F[z];
122 }
123 int rs=find(y);
124 z=wtf[y];
125 for(;;) {
126 f[z]-=w;
127 if(z==y) break;
128 z=F[z];
129 }
130 return rs;
131 }
132 } return x;
133 }
134
135 LL qry(int x) {
136 LL rs=0; int tp=x;
137 rs+=g[x];
138 int pr=x; x=F[x];
139 while(x) {
140 rs+=g[x]-gtf[pr]+(LL)(f[x]-f[pr])*get_dis(x,tp);
141 pr=x; x=F[x];
142 }
143 return rs;
144 }
145
146 //#define DEBUG
147 int main() {
148 #ifdef DEBUG
149 freopen("std.in","r",stdin);
150 //freopen(".out","w",stdout);
151 #endif
152 read(n); read(Q);
153 For(i,1,n-1) {
154 int x,y,z;
155 read(x); read(y); read(z);
156 add(x,y,z);
157 }
158 dfs(1,0);
159 pre_RMQ();
160 rt=0; sznow=n;
161 get_rt(1,0);
162 RT=rt;
163 solve(rt,0);
164 while(Q--) {
165 int x,y;
166 read(x); read(y);
167 d[x]+=y;
168 change(x,x,y);
169 x=find(RT);
170 printf("%lld\n",qry(x));
171 }
172 return 0;
173 }
174 /*
175 10 5
176 1 2 1
177 2 3 1
178 2 4 1
179 1 5 1
180 2 6 1
181 2 7 1
182 5 8 1
183 7 9 1
184 1 10 1
185 3 1
186 2 1
187 8 1
188 3 1
189 4 1
190 */
一棵树,有点权,边权均为1.支持修改某个点的点权和查询距离某个点不超过k的所有点的点权和.
点分树建出来,每个点维护它管辖范围内所有点按距离排序的点权和,用线段树或者数状数组(其实我一开始想的是用treap..)
每个点再开一个数状数组维护它管辖范围内所有点按与父亲的距离排序的点权和
数状数组要把每一层开在一起,才不会炸空间
查询的时候沿着父亲跑,若查询点到当前点的距离dis<=k,ans加上距当前点小于等于k-dis的距离和,减去上一个点中据父亲小于等于k-dis的距离和
需要注意当dis>k时并不能跳出,应该继续沿着父亲跑.
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #define For(i,a,b) for(int i=(a);i<=(b);i++)
12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
13 const int N=200007;
14 typedef long long LL;
15 typedef double db;
16 using namespace std;
17 int n,m,v[N];
18
19 template<typename T> void read(T &x) {
20 char ch=getchar(); x=0; T f=1;
21 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
22 if(ch=='-') f=-1,ch=getchar();
23 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
24 }
25
26 int sum[2][30][N],st[N],ed[N];
27 void add(int o,int id,int x,int v) {
28 for(int i=x;i<=n;i+=(i&(-i)))
29 sum[o][id][i]+=v;
30 }
31
32 int qry(int o,int id,int x) {
33 int rs=0;
34 if(x<=0) return rs;
35 for(int i=x;i;i-=(i&(-i)))
36 rs+=sum[o][id][i];
37 return rs;
38 }
39
40 int ecnt,fir[N],nxt[N<<1],to[N<<1];
41 void ADD(int u,int v) {
42 nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
43 nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
44 }
45
46 int dfs_clock,dfn[N],tid[N<<1],R[N];
47 void dfs(int x,int fa) {
48 dfn[x]=++dfs_clock;
49 tid[dfn[x]]=x;
50 R[x]=R[fa]+1;
51 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
52 dfs(to[i],x);
53 ++dfs_clock;
54 tid[dfs_clock]=x;
55 }
56 }
57
58 int ST[N<<1][25];
59 void pre_RMQ() {
60 For(i,1,dfs_clock-1) ST[i][0]=(R[tid[i]]<R[tid[i+1]])?tid[i]:tid[i+1];
61 For(j,1,20)
62 For(i,1,dfs_clock) if(i+(1<<j)<=dfs_clock)
63 ST[i][j]=R[ST[i][j-1]]<R[ST[i+(1<<j-1)][j-1]]?ST[i][j-1]:ST[i+(1<<j-1)][j-1];
64 }
65
66 int lca(int x,int y) {
67 if(x==y) return x;
68 x=dfn[x]; y=dfn[y];
69 if(x>y) swap(x,y);
70 int k=0; while(x+(1<<k)<=y) k++; if(k) k--;
71 return R[ST[x][k]]<R[ST[y-(1<<k)][k]]?ST[x][k]:ST[y-(1<<k)][k];
72 }
73
74 int get_dis(int x,int y) { return R[x]+R[y]-2LL*R[lca(x,y)]; }
75
76 int rt,sznow,vis[N],sz[N],mxson[N];
77 void get_rt(int x,int fa) {
78 sz[x]=mxson[x]=1;
79 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa&&!vis[to[i]]) {
80 get_rt(to[i],x);
81 sz[x]+=sz[to[i]];
82 mxson[x]=max(mxson[x],sz[to[i]]);
83 }
84 mxson[x]=max(mxson[x],sznow-sz[x]);
85 if(!rt||mxson[rt]>mxson[x]) rt=x;
86 }
87
88 int len[30];
89 int F[N],D[N];
90 void dfs2(int x,int fa,int rt) {
91 sz[x]=1;
92 add(0,D[rt],st[rt]+get_dis(x,rt)+1,v[x]);
93 if(F[rt]) add(1,D[rt],st[rt]+get_dis(x,F[rt]),v[x]);
94 for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]&&to[i]!=fa) {
95 dfs2(to[i],x,rt);
96 sz[x]+=sz[to[i]];
97 }
98 }
99
100 void solve(int x,int FA,int dep) {
101 F[x]=FA;
102 vis[x]=1;
103 D[x]=dep;
104 dfs2(x,0,x);
105 for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) {
106 rt=0; sznow=sz[to[i]];
107 get_rt(to[i],0);
108 st[rt]=len[dep+1];
109 len[dep+1]+=sznow;
110 solve(rt,x,dep+1);
111 }
112 }
113
114 void change(int x,int y,int V) {
115 while(x) {
116 add(0,D[x],st[x]+get_dis(x,y)+1,V);
117 if(F[x]) add(1,D[x],st[x]+get_dis(F[x],y),V);
118 x=F[x];
119 }
120 }
121
122 int ans;
123 int get_ans(int x,int k) {
124 int rs=qry(0,D[x],min(ed[x],st[x]+k+1))-qry(0,D[x],st[x]);
125 int tp=x,pr=x; x=F[x];
126 while(x) {
127 int kk=get_dis(x,tp); kk=k-kk;
128 if(kk>=0) rs-=qry(1,D[pr],min(ed[pr],st[pr]+kk))-qry(1,D[pr],st[pr]);
129 if(kk>=0) rs+=qry(0,D[x],min(ed[x],st[x]+kk+1))-qry(0,D[x],st[x]);
130 pr=x; x=F[x];
131 }
132 return rs;
133 }
134
135 //#define DEBUG
136 int main() {
137 #ifdef DEBUG
138 freopen("std.in","r",stdin);
139 //freopen(".out","w",stdout);
140 #endif
141 read(n); read(m);
142 For(i,1,n) read(v[i]);
143 For(i,2,n) {
144 int x,y;
145 read(x); read(y);
146 ADD(x,y);
147 }
148 dfs(1,0);
149 pre_RMQ();
150 sznow=n; rt=0;
151 get_rt(1,0);
152 solve(rt,0,1);
153 For(i,1,n) ed[i]=st[i]+sz[i];
154 For(ti,1,m) {
155 int o,x,y,k;
156 read(o);
157 if(o==0) {
158 read(x); read(k);
159 x^=ans; k^=ans;
160 ans=get_ans(x,k);
161 printf("%d\n",ans);
162 }
163 else {
164 read(x); read(y);
165 x^=ans; y^=ans;
166 change(x,x,y-v[x]);
167 v[x]=y;
168 }
169 }
170 return 0;
171 }
172 /*
173 8 1
174 1 10 100 1000 10000 100000 1000000 10000000
175 1 2
176 1 3
177 2 4
178 2 5
179 3 6
180 3 7
181 3 8
182 0 3 1
183 */
码力实在弱得令人发指,各种bug....之前看到有人说码力弱本质是题没有想清楚.即使努力先想清楚再写,看了代码一遍又一遍也没有发现问题,只有调试才能发现自己还是有些地方没有想清楚..
5.7upd
4372: 烁烁的游戏
现在写这题感觉是模板呀,和震波差不多只是因为最大都到n所以用动态开点的线段树维护.
每个点维护它分治树中都子树中的加都操作如果到它这里还可以继续延伸都话,按还可以延伸都长度排序,线段树维护权值和
每个点分治子树对它都贡献在加的时候直接算到点上,剩下都就是沿着父亲跑,然后套路的每次是父亲中的减去在它子树中的.
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #include<map>
12 #define For(i,a,b) for(int i=(a);i<=(b);i++)
13 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
14 const int N=1e5+7;
15 typedef long long LL;
16 typedef double db;
17 using namespace std;
18 int n,m;
19 char o[10];
20
21 template<typename T> void read(T &x) {
22 char ch=getchar(); x=0; T f=1;
23 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
24 if(ch=='-') f=-1,ch=getchar();
25 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
26 }
27
28 int ecnt,fir[N],nxt[N<<1],to[N<<1];
29 void add(int u,int v) {
30 nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
31 nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
32 }
33
34 int dfn[N<<1],tid[N<<1],R[N<<1],dfs_clock;
35 void dfs(int x,int fa) {
36 R[x]=R[fa]+1;
37 dfn[x]=++dfs_clock;
38 tid[dfn[x]]=x;
39 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
40 dfs(to[i],x);
41 tid[++dfs_clock]=x;
42 }
43 }
44
45 int st[N<<1][20];
46 void pre_st() {
47 For(i,1,dfs_clock-1) st[i][0]=R[tid[i]]<R[tid[i+1]]?tid[i]:tid[i+1];
48 For(j,1,17) For(i,1,dfs_clock) if(i+(1<<j)<=dfs_clock)
49 st[i][j]=R[st[i][j-1]]<R[st[i+(1<<j-1)][j-1]]?st[i][j-1]:st[i+(1<<j-1)][j-1];
50 }
51
52 int lca(int x,int y) {
53 if(x==y) return x;
54 x=dfn[x]; y=dfn[y];
55 if(x>y) swap(x,y);
56 int k;
57 for(k=0;x+(1<<k)<=y;k++); if(k) k--;
58 return R[st[x][k]]<R[st[y-(1<<k)][k]]?st[x][k]:st[y-(1<<k)][k];
59 }
60
61 int dis(int x,int y) { return R[x]+R[y]-2*R[lca(x,y)]; }
62
63 int rt,f[N],sz[N],mson[N],vis[N],sznow;
64 void get_root(int x,int fa) {
65 sz[x]=mson[x]=1;
66 for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]&&to[i]!=fa) {
67 get_root(to[i],x);
68 sz[x]+=sz[to[i]];
69 mson[x]=max(mson[x],sz[to[i]]);
70 }
71 mson[x]=max(mson[x],sznow-sz[x]);
72 if(!rt||mson[x]<mson[rt]) rt=x;
73 }
74
75 void dfs2(int x,int fa) {
76 sz[x]=1;
77 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa&&!vis[to[i]]) {
78 dfs2(to[i],x); sz[x]+=sz[to[i]];
79 }
80 }
81
82 void solve(int x,int FA) {
83 f[x]=FA;
84 vis[x]=1;
85 dfs2(x,0);
86 for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) {
87 rt=0; sznow=sz[to[i]];
88 get_root(to[i],0); solve(rt,x);
89 }
90 }
91
92 int rt1[N],rt2[N],sg[N*200],ch[N*200][2],tot;
93 #define lc ch[x][0]
94 #define rc ch[x][1]
95 #define mid ((l+r)>>1)
96 void update(int &x,int l,int r,int pos,int v) {
97 if(!x) x=++tot;
98 if(l==r) { sg[x]+=v; return; }
99 if(pos<=mid) update(lc,l,mid,pos,v);
100 else update(rc,mid+1,r,pos,v);
101 sg[x]=sg[lc]+sg[rc];
102 }
103
104 int qry(int x,int l,int r,int ql,int qr) {
105 if(!x) return 0;
106 if(l>=ql&&r<=qr) return sg[x];
107 if(qr<=mid) return qry(lc,l,mid,ql,qr);
108 if(ql>mid) return qry(rc,mid+1,r,ql,qr);
109 return qry(lc,l,mid,ql,qr)+qry(rc,mid+1,r,ql,qr);
110 }
111
112 int Ans[N];
113 void change(int x,int d,int w) {
114 d=min(d,n); int z=x;
115 while(x) {
116 int d1=dis(x,z);
117 if(d1<=d) {
118 Ans[x]+=w;
119 if(d-d1>0) update(rt1[x],1,n,d-d1,w);
120 }
121 if(f[x]) {
122 int d2=dis(f[x],z);
123 if(d-d2>0) update(rt2[x],1,n,d-d2,w);
124 }
125 x=f[x];
126 }
127 }
128
129 int qry(int x) {
130 int rs=Ans[x],z=x;
131 while(f[x]) {
132 int d=dis(z,f[x]);
133 rs+=qry(rt1[f[x]],1,n,d,n);
134 rs-=qry(rt2[x],1,n,d,n);
135 x=f[x];
136 }
137 return rs;
138 }
139
140 //#define DEBUG
141 int main() {
142 #ifdef DEBUG
143 freopen("4372.in","r",stdin);
144 freopen("4372.out","w",stdout);
145 #endif
146 read(n); read(m);
147 For(i,1,n-1) {
148 int u,v;
149 read(u); read(v); add(u,v);
150 }
151 dfs(1,0);
152 pre_st();
153 rt=0; sznow=n;
154 get_root(1,0);
155 solve(rt,0);
156 int tptot=0;
157 while(m--) {
158 scanf("%s",o);
159 int x,d,w;
160 if(tot>=10000690) {
161 int debug=1;
162 }
163 if(o[0]=='Q') {
164 tptot++;
165 if(tptot==46217) {
166 int debug=1;
167 }
168 read(x);
169 printf("%d\n",qry(x));
170 }
171 else {
172 read(x); read(d); read(w);
173 change(x,d,w);
174 }
175 }
176 //printf("%d\n",tot);
177 return 0;
178 }