[动态点分治] BZOJ3730: 震波

来源:互联网 发布:热血传奇手游源码 编辑:程序博客网 时间:2024/05/21 17:50

题意

给定N个点的一棵边权都为1的树,每个点有点权 。M次操作,两种类型
1.单点点权修改。
2.给出x和k,询问到x的距离不超过K的所有点权和。
操作加密,强制在线。
N,M<=100000

题解

动态点分治。
同样把信息收集到根。对于每个点分树,把所有点放到一个树状数组中,数状数组的下标即是到根的距离。要注意相同子树中的东西计算重复了,为了抠去重复部分,还需要对每个点分树再开一个数状数组,维护其中的点到父点分树的根的距离。这样修改和询问都是暴力爬树高,修改时在途中进行树状数组的单点修改,询问的话每次统计一下经过当前根的路径对应的权值和即可。

#include<cstdio>#include<queue>#include<algorithm>using namespace std;const int maxn=100005, maxe=200005;int n,m,w[maxn],last_print;int fir[maxn],nxt[maxe],son[maxe],tot;bool vis[maxn];int sz[maxn];//------------------------------------------------------------------------int rt,allmin,allsz,MaxD,d[maxn];int dfs_info(int x,int fa){    sz[x]=1;    for(int j=fir[x];j;j=nxt[j]) if(son[j]!=fa&&!vis[son[j]]){        d[son[j]]=d[x]+1; MaxD=max(MaxD,d[son[j]]);        dfs_info(son[j],x); sz[x]+=sz[son[j]];    }}void dfs_G(int x,int fa){     int _max=0;       for(int j=fir[x];j;j=nxt[j]) if(son[j]!=fa&&!vis[son[j]]){        dfs_G(son[j],x);          _max=max(_max,sz[son[j]]);       }       if(allmin>max(_max,allsz-sz[x])) allmin=max(_max,allsz-sz[x]), rt=x;  }int find_G(int x){    allmin=1e+9;     MaxD=d[x]=0; dfs_info(x,0); allsz=sz[x];    dfs_G(x,0);    return rt;}//------------------------------------------------------------------------int dep[maxn],anc[maxn][25];void dfs_LCA(int x,int fa){    anc[x][0]=fa;    for(int j=1;j<=20;j++) anc[x][j]=anc[anc[x][j-1]][j-1];    for(int j=fir[x];j;j=nxt[j]) if(son[j]!=fa)    dep[son[j]]=dep[x]+1, dfs_LCA(son[j],x);}int LCA(int x,int y){    if(dep[x]<dep[y]) swap(x,y);    for(int j=20;j>=0;j--) if(dep[anc[x][j]]>=dep[y]) x=anc[x][j];     if(x==y) return x;    for(int j=20;j>=0;j--) if(anc[x][j]!=anc[y][j]) x=anc[x][j], y=anc[y][j];    return anc[x][0];}int getDis(int x,int y){    return dep[x]+dep[y]-dep[LCA(x,y)]*2;}//------------------------------------------------------------------------vector< int > bit[maxn][2];void bit_Updata(int k1,int k2,int x,int val){    int len=bit[k1][k2].size()-1;    for(x++;x<=len;x+=(x&(-x))) bit[k1][k2][x]+=val;}int bit_Query(int k1,int k2,int x){    int res=0, len=bit[k1][k2].size()-1;    for(x=min(x+1,len);x;x-=(x&(-x))) res+=bit[k1][k2][x];    return res;}//------------------------------------------------------------------------int prt[maxn];void dfs_push(int x,int fa,int id){    bit_Updata(id,0,getDis(x,id),w[x]);     if(prt[id]) bit_Updata(id,1,getDis(x,prt[id]),w[x]);        for(int j=fir[x];j;j=nxt[j]) if(son[j]!=fa&&!vis[son[j]]) dfs_push(son[j],x,id);}void DivTree(int x,int faG){    int G=find_G(x);     prt[G]=faG; vis[G]=true;    bit[G][0].resize(allsz+3); bit[G][1].resize(allsz+3);     dfs_push(G,0,G);    for(int j=fir[G];j;j=nxt[j]) if(!vis[son[j]]) DivTree(son[j],G);}void Updata(int x,int val){    for(int y=x;y;y=prt[y]){        bit_Updata(y,0,getDis(x,y),val-w[x]);        if(prt[y]) bit_Updata(y,1,getDis(x,prt[y]),val-w[x]);           }}int Query(int x,int K){    int res=bit_Query(x,0,K);    for(int y=x;prt[y];y=prt[y]) if(K>=getDis(x,prt[y]))     res+=bit_Query(prt[y],0,K-getDis(x,prt[y]))-bit_Query(y,1,K-getDis(x,prt[y]));    return res;}//------------------------------------------------------------------------void add(int x,int y){    son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot;}int getint(){    int res=0; char ch=getchar();    while(!('0'<=ch&&ch<='9')) ch=getchar();    while('0'<=ch&&ch<='9') res=res*10+ch-'0', ch=getchar();    return res;}int main(){    freopen("bzoj3730.in","r",stdin);    freopen("bzoj3730.out","w",stdout);    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) w[i]=getint();    for(int i=1;i<=n-1;i++){        int x=getint(),y=getint();         add(x,y); add(y,x);    }    dfs_LCA(1,0);    DivTree(1,0);    while(m--){        int pd=getint(),x=getint(),y=getint();        x^=last_print; y^=last_print;        if(!pd) printf("%d\n",last_print=Query(x,y));           else Updata(x,y), w[x]=y;    }    return 0;}
0 0
原创粉丝点击