AmazingCounters.com

[BZOJ]4372: 烁烁的游戏

Time Limit: 30 Sec  Memory Limit: 512 MB

Description

  背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。
  题意:
  给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠。
  烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠。皮皮鼠会被烁烁吸引,所以会一直待在节点上不动。
  烁烁很好奇,在当前时刻,节点u有多少个他的好朋友---皮皮鼠。
  大意:
  给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:
  Q x:询问x的点权。
  M x d w:将树上与节点x距离不超过d的节点的点权均加上w。

Input

  第一行两个正整数:n,m
  接下来的n-1行,每行三个正整数u,v,代表u,v之间有一条边。
  接下来的m行,每行给出上述两种操作中的一种。

Output

  对于每个Q操作,输出当前x节点的皮皮鼠数量。

Sample Input

  7 6
  1 2
  1 4
  1 5
  2 3
  2 7
  5 6
  M 1 1 2
  Q 5
  M 2 2 3
  Q 3
  M 1 2 1
  Q 2

Sample Output

  2
  3
  6

HINT

  数据范围:
  n,m<=10^5,|w|<=10^4
  注意:w不一定为正整数,因为烁烁可能把皮皮鼠吓傻了。

Solution

  动态点分治。先建出点分治的分治结构,修改一个点的时候,对于每一层该点所在的分治结构,开一个线段树在d减该点到重心距离(即到其他子树的最远距离)的位置加上w,查询同样对每一层的线段树查询大等于该点到重心距离的权值和,为了避免统计到自己子树内的信息,每一层分治结构的每个大的子树都再开一个线段树存储子树内信息。总复杂度$O(nlog^{2}n)$。

Code

#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
    int x,f=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=0;
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
    return f?x:-x;
}
#define MN 100000
#define K 20
#define ND 30000000
struct edge{int nx,t;}e[MN*2+5];
int h[MN+5],en,sz,rt,rts,u[MN+5],s[MN+5];
int fa[MN+5],dep[MN+5],t1[MN+5],t2[K][MN+5],tn,d[K][MN+5];
struct node{int l,r,s;}t[ND+5];
inline void ins(int x,int y)
{
    e[++en]=(edge){h[x],y};h[x]=en;
    e[++en]=(edge){h[y],x};h[y]=en;
}
int query(int k,int l,int r,int ql,int qr)
{
    if(l==ql&&r==qr)return t[k].s;
    int mid=l+r>>1;
    if(qr<=mid)return query(t[k].l,l,mid,ql,qr);
    if(ql>mid)return query(t[k].r,mid+1,r,ql,qr);
    return query(t[k].l,l,mid,ql,mid)+query(t[k].r,mid+1,r,mid+1,qr);
}
void add(int&k,int l,int r,int x,int ad)
{
    if(!k)k=++tn;
    if(l==r){t[k].s+=ad;return;}
    int mid=l+r>>1;
    if(x<=mid)add(t[k].l,l,mid,x,ad);
    else add(t[k].r,mid+1,r,x,ad);
    t[k].s=t[t[k].l].s+t[t[k].r].s;
}
void getrt(int x,int fa)
{
    int mx=0;
    s[x]=1;
    for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa&&!u[e[i].t])
        getrt(e[i].t,x),s[x]+=s[e[i].t],mx=max(mx,s[e[i].t]);
    mx=max(mx,sz-s[x]);
    if(mx<rts)rts=mx,rt=x;
}
void dfs(int x,int fa,int dep)
{
    s[x]=1;d[dep][x]=d[dep][fa]+1;
    for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa&&!u[e[i].t])
        t2[dep][e[i].t]=t2[dep][x],dfs(e[i].t,x,dep),s[x]+=s[e[i].t];
}
void solve(int x)
{
    int i;u[x]=1;
    for(i=h[x];i;i=e[i].nx)if(!u[e[i].t])
        t2[dep[x]][e[i].t]=++tn,dfs(e[i].t,x,dep[x]);
    for(i=h[x];i;i=e[i].nx)if(!u[e[i].t])
        sz=rts=s[e[i].t],getrt(e[i].t,x),
        fa[rt]=x,dep[rt]=dep[x]+1,solve(rt);
}
int main()
{
    int n,m,i,x,y,w;char s[5];
    n=read();m=read();
    for(i=1;i<n;++i)ins(read(),read());
    sz=rts=n;getrt(1,0);solve(rt);
    while(m--)
    {
        scanf("%s",s);
        if(s[0]=='M')
        {
            x=read();y=read();w=read();
            for(i=x;i;i=fa[i])if(y>=d[dep[i]][x])
            {
                add(t1[i],0,MN,y-d[dep[i]][x],w);
                if(t2[dep[i]][x])add(t2[dep[i]][x],0,MN,y-d[dep[i]][x],w);
            }
        }
        else
        {
            x=read();w=0;
            for(i=x;i;i=fa[i])
                w+=query(t1[i],0,MN,d[dep[i]][x],MN)-query(t2[dep[i]][x],0,MN,d[dep[i]][x],MN);
            printf("%d\n",w);
        }
    }
}

 

posted on 2017-06-05 16:44  ditoly  阅读(819)  评论(0编辑  收藏  举报