[BZOJ4372][动态树分治(点分树)][动态开点线段树]烁烁的游戏

题意


给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:
Q x:询问x的点权
M x d w:将树上与节点x距离不超过d的节点的点权均加上w


dfs出点分树

每个重心要记录这个重心以下的子点分树的修改信息,可以用区间覆盖单店查询的线段树维护,因为会有重复的部分,每个重心还要再开一棵线段树记录重复的部分

#include 
#include 
#include 
#define N 100010

using namespace std;

int n,m,cnt,u,v,mn,isz,id;
int G[N],vis[N],dpt[N],p[N],rt[N],rt1[N];
int fa[N][25];
char op;
struct edge{
  int t,nx;
}E[N<<1];
struct sgm{
  int l,r,ls,rs,tot,flg;
}T[N*150];

inline void Read(int &x){
  char c=getchar();x=0; int f=1;
  for(;c>57||c<48;c=getchar())if(c=='-')f=-1;
  for(;c>=48&&c<=57;x=x*10+c-48,c=getchar()); x*=f;
}

inline void Insert(int u,int v){
  E[++cnt].t=v; E[cnt].nx=G[u]; G[u]=cnt;
  E[++cnt].t=u; E[cnt].nx=G[v]; G[v]=cnt;
}

int get_size(int x,int f){
  int sz=1;
  for(int i=G[x];i;i=E[i].nx)
    if(E[i].t!=f&&!vis[E[i].t]) sz+=get_size(E[i].t,x);
  return sz;
}

int get_root(int x,int f,int &rt){
  int sz=1,maxx=0;
  for(int i=G[x];i;i=E[i].nx)
    if(E[i].t!=f&&!vis[E[i].t]){
      int k=get_root(E[i].t,x,rt);
      if(k>maxx) maxx=k;
      sz+=k;
    }
  if(isz-sz>maxx) maxx=isz-sz;
  if(maxxreturn sz;
}

int dfs(int x){
  isz=get_size(x,0);
  mn=1<<30;
  int rt;
  get_root(x,0,rt); vis[rt]=1;
  for(int i=G[rt];i;i=E[i].nx)
    if(!vis[E[i].t]) p[dfs(E[i].t)]=rt;
  return rt;
}

void explore(int x,int f){
  dpt[x]=dpt[f]+1; fa[x][0]=f;
  for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
  for(int i=G[x];i;i=E[i].nx)
    if(E[i].t!=f) explore(E[i].t,x);
}

inline int LCA(int x,int y){
  if(dpt[x]return LCA(y,x);
  for(int i=20;~i;i--)
    if(dpt[fa[x][i]]>=dpt[y]) x=fa[x][i];
  if(x==y) return x;
  for(int i=20;~i;i--)
    if(fa[x][i]!=fa[y][i])
      x=fa[x][i],y=fa[y][i];
  return fa[x][0];
}

inline int dis(int x,int y){
  return dpt[x]+dpt[y]-2*dpt[LCA(x,y)];
}

int query(int g,int x){
  if(!g) return 0;
  if(T[g].l==T[g].r) return T[g].tot;
  int mid=T[g].l+T[g].r>>1;
  if(x<=mid) return query(T[g].ls,x)+T[g].tot;
  else return query(T[g].rs,x)+T[g].tot;
}

inline int query(int x){
  int dist=0,r=query(rt[x],dist);
  for(int i=x;p[i];i=p[i]){
    dist=dis(p[i],x);
    r+=query(rt[p[i]],dist)+query(rt1[i],dist);
  }
  return r;
}

void add(int &g,int L,int R,int l,int r,int v){
  if(!g){
    g=++id,T[g].l=L,T[g].r=R;
    T[g].flg=T[g].tot=0;
  }
  if(L==l&&r==R){
    T[g].tot+=v;
    return ;
  }
  int mid=L+R>>1;
  if(r<=mid) add(T[g].ls,L,mid,l,r,v);
  else if(l>mid) add(T[g].rs,mid+1,R,l,r,v);
  else add(T[g].ls,L,mid,l,mid,v),add(T[g].rs,mid+1,R,mid+1,r,v);
}

inline void add(int x,int d,int v){
  int dist;
  add(rt[x],0,n,0,d,v);
  for(int i=x;p[i];i=p[i]){
    dist=dis(p[i],x);
    if(dist>d) continue;
    add(rt1[i],0,n,0,d-dist,-v);
    add(rt[p[i]],0,n,0,d-dist,v);
  }
}

int main(){
  Read(n); Read(m);
  for(int i=1;i1,0);
  dfs(1);
  for(int i=1;i<=m;i++){
    while((op=getchar())!='Q'&&op!='M');
    if(op=='Q'){
      int x; Read(x);
      printf("%d\n",query(x)); 
    }
    else{
      int x,d,v;
      Read(x); Read(d); Read(v);
      add(x,d,v);
    }
  }
  return 0;
}


你可能感兴趣的:(线段树,点分树)