bzoj 4372 烁烁的游戏——动态点分治+树状数组

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372

和 bzoj 3070 震波 是一个套路。注意区间修改的话,树状数组不能表示 dis = 0 的位置,所以要手动改父亲的点权数组。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
const int N=1e5+5,K=20;
int n,w[N],hd[N],xnt,to[N<<1],nxt[N<<1],siz[N],rt,mn;
int pre[N][K],dep[N],dis[N][K],fs[N],gs[N]; vector<ll> f[N],g[N];
bool vis[N];
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void add(int cr,int x,int k){for(x=Mn(x,fs[cr]);x;x-=(x&-x))f[cr][x]+=k;}
ll qry(int cr,int x){ll ret=0;for(;x&&x<=fs[cr];x+=(x&-x))ret+=f[cr][x];return ret;}
void addx(int cr,int x,int k){for(x=Mn(x,gs[cr]);x;x-=(x&-x))g[cr][x]+=k;}
ll qryx(int cr,int x){ll ret=0;for(;x&&x<=gs[cr];x+=(x&-x))ret+=g[cr][x];return ret;}
void getrt(int cr,int fa,int s)
{
  siz[cr]=1;int mx=0;
  for(int i=hd[cr],v;i;i=nxt[i])
    if(!vis[v=to[i]]&&v!=fa)
      {
    getrt(v,cr,s);siz[cr]+=siz[v];mx=Mx(mx,siz[v]);
      }
  mx=Mx(mx,s-siz[cr]); if(mx<mn)mn=mx,rt=cr;
}
void dfs(int cr,int fa,int ds)
{
  pre[cr][++dep[cr]]=rt;dis[cr][dep[cr]]=ds;
  for(int i=hd[cr],v;i;i=nxt[i])
    if(!vis[v=to[i]]&&v!=fa)dfs(v,cr,ds+1);
}
void init(int cr,int s)
{
  vis[cr]=1;fs[cr]=mn;gs[cr]=(mn<<1)+1;
  f[cr].resize(fs[cr]+1);g[cr].resize(gs[cr]+1);
  dfs(cr,0,0);
  for(int i=hd[cr],v;i;i=nxt[i])
    if(!vis[v=to[i]])
      {
    int ts=(siz[v]<siz[cr]?siz[v]:s-siz[cr]);
    mn=N;getrt(v,cr,ts);init(rt,ts);
      }
}
void mdfy(int cr,int d,int k)
{
  add(cr,d,k); w[cr]+=k;
  for(int i=dep[cr]-1;i;i--)
    {
      if(dis[cr][i]>d)continue;
      add(pre[cr][i],d-dis[cr][i],k); w[pre[cr][i]]+=k;/////
      addx(pre[cr][i+1],d-dis[cr][i],k);
    }
}
ll query(int cr)
{
  ll ret=w[cr];
  for(int i=dep[cr]-1;i;i--)
    {
      ret+=qry(pre[cr][i],dis[cr][i]);
      ret-=qryx(pre[cr][i+1],dis[cr][i]);
    }
  return ret;
}
int main()
{
  n=rdn(); int Q=rdn();
  for(int i=1,u,v;i<n;i++)
    u=rdn(),v=rdn(),add(u,v),add(v,u);
  mn=N;getrt(1,0,n);init(rt,n);
  int x,d,k;char ch[5];
  while(Q--)
    {
      scanf("%s",ch);x=rdn();
      if(ch[0]=='Q')printf("%lld\n",query(x));
      else
    {
      d=rdn(); k=rdn(); mdfy(x,d,k);
    }
    }
  return 0;
}

 

posted on 2018-12-27 20:55  Narh  阅读(192)  评论(0编辑  收藏  举报

导航