BZOJ - 3730 震波 (点分树+树状数组)
作者:互联网
两种操作:
1.查询与树上结点x距离不超过k的结点权值之和
2.将结点x的权值修改为y
点分树模板题。
首先考虑一种比较暴力的做法:用树形dp的思想,将树转化成有根树,设f[u][k]为结点u子树下与其距离不超过k的点权和,则ans(x,k)=f[u][k]+f[fa[u]][k-1]-f[u][k-2]+f[fa[fa[u]]][k-2]-f[fa[u]][k-3]...,可如果树太高的话就GG了,要是能把树高变成logn级别的就好了。
建立点分树(点分治过程中形成的树),每个结点维护两个树状数组,一个维护以该结点为重心的各个距离上的权值和,一个维护其虚父亲(点分树上的父亲)在“该结点方向”上的各个距离上的权值和(用于容斥)。还要另外维护一个数据结构用于求原树上两点之间距离(树剖效率比较高),修改和询问就从当前结点开始不断向上跳即可。(点分树的树高是logn级别的,可以暴力往上跳)
总复杂度$O(nlogn+qlog^2n)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10,inf=0x3f3f3f3f; 5 struct E {int v,nxt;} e[N<<1]; 6 int a[N],hd[N],ne,n,Q,siz[N],mx[N],vis[N],RT,tot,cnt[N],fa[N]; 7 int buf[N*40],*ptr=buf; 8 struct BIT { 9 int *c,n; 10 int lb(int x) {return x&-x;} 11 void add(int u,int x) {for(; u<=n; u+=lb(u))c[u]+=x;} 12 int get(int u) {int ret=0; for(u=min(u,n); u; u-=lb(u))ret+=c[u]; return ret;} 13 void build(int* a) { 14 for(int i=1; i<=n; ++i)c[i]=a[i]; 15 for(int i=1; i<=n; ++i)if(i+lb(i)<=n)c[i+lb(i)]+=c[i]; 16 } 17 } c[N][2]; 18 BIT newBIT(int n) {BIT t= {ptr,n}; ptr+=n+1; return t;} 19 struct LCA { 20 int fa[N],son[N],dep[N],siz[N],top[N]; 21 void dfs1(int u,int f,int d) { 22 fa[u]=f,son[u]=0,dep[u]=d,siz[u]=1; 23 for(int i=hd[u]; ~i; i=e[i].nxt) { 24 int v=e[i].v; 25 if(v==fa[u])continue; 26 dfs1(v,u,d+1),siz[u]+=siz[v]; 27 if(siz[v]>siz[son[u]])son[u]=v; 28 } 29 } 30 void dfs2(int u,int tp) { 31 top[u]=tp; 32 if(son[u])dfs2(son[u],tp); 33 for(int i=hd[u]; ~i; i=e[i].nxt) { 34 int v=e[i].v; 35 if(v==fa[u]||v==son[u])continue; 36 dfs2(v,v); 37 } 38 } 39 int lca(int u,int v) { 40 for(; top[u]!=top[v]; u=fa[top[u]])if(dep[top[u]]<dep[top[v]])swap(u,v); 41 return dep[u]<dep[v]?u:v; 42 } 43 int dis(int u,int v) {return dep[u]+dep[v]-2*dep[lca(u,v)];} 44 } lca; 45 void link(int u,int v) {e[ne]= (E) {v,hd[u]},hd[u]=ne++;} 46 void getrt(int u,int f) { 47 siz[u]=1,mx[u]=0; 48 for(int i=hd[u]; ~i; i=e[i].nxt) { 49 int v=e[i].v; 50 if(vis[v]||v==f)continue; 51 getrt(v,u),siz[u]+=siz[v],mx[u]=max(mx[u],siz[v]); 52 } 53 mx[u]=max(mx[u],tot-siz[u]); 54 if(mx[u]<mx[RT])RT=u; 55 } 56 void getdis(int u,int f,int d) { 57 cnt[d]+=a[u]; 58 for(int i=hd[u]; ~i; i=e[i].nxt) { 59 int v=e[i].v; 60 if(vis[v]||v==f)continue; 61 getdis(v,u,d+1); 62 } 63 } 64 void cal(int u,int f) { 65 int m=1; 66 for(; cnt[m]; ++m); 67 --m; 68 c[u][f]=newBIT(m); 69 c[u][f].build(cnt); 70 for(int i=1; i<=m; ++i)cnt[i]=0; 71 } 72 void solve(int u) { 73 getdis(u,0,1),cal(u,0),vis[u]=1; 74 for(int i=hd[u]; ~i; i=e[i].nxt) { 75 int v=e[i].v; 76 if(vis[v])continue; 77 getdis(v,0,1),RT=0,tot=siz[v]; 78 getrt(v,0),cal(RT,1),fa[RT]=u,solve(RT); 79 } 80 } 81 void upd(int u,int x) { 82 x-=a[u],a[u]+=x; 83 int dis=0; 84 c[u][0].add(dis+1,x); 85 for(int v=u; fa[v]; v=fa[v]) { 86 dis=lca.dis(u,fa[v]); 87 c[fa[v]][0].add(dis+1,x),c[v][1].add(dis,x); 88 } 89 } 90 int qry(int u,int d) { 91 int ret=0,dis=d; 92 ret+=c[u][0].get(dis+1); 93 for(int v=u; fa[v]; v=fa[v]) { 94 dis=d-lca.dis(u,fa[v]); 95 if(dis>=0)ret+=c[fa[v]][0].get(dis+1)-c[v][1].get(dis); 96 } 97 return ret; 98 } 99 int main() { 100 memset(hd,-1,sizeof hd),ne=0; 101 scanf("%d%d",&n,&Q); 102 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 103 for(int i=1; i<n; ++i) { 104 int u,v; 105 scanf("%d%d",&u,&v); 106 link(u,v); 107 link(v,u); 108 } 109 mx[0]=inf,RT=0,tot=n,getrt(1,0),fa[RT]=0,solve(RT); 110 lca.dfs1(1,0,1),lca.dfs2(1,1); 111 for(int la=0; Q--;) { 112 int f,u,x; 113 scanf("%d%d%d",&f,&u,&x); 114 u^=la,x^=la; 115 if(f==0)printf("%d\n",la=qry(u,x)); 116 else upd(u,x); 117 } 118 return 0; 119 }
标签:结点,int,top,son,fa,点分树,震波,权值,BZOJ 来源: https://www.cnblogs.com/asdfsag/p/12513986.html