BZOJ - 3730 震波 (点分树+树状数组)

和自甴很熟 提交于 2020-03-18 13:45:08

两种操作:

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 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!