[bzoj4372]烁烁的游戏

来自FallDream的博客,未经允许,请勿转载,谢谢。


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

n,m<=10^5 wi<=10^4

 

让离树上一个点距离小等于d的点的权值加上一个数,这个是可以点分来做的,每次分治都统计一个子树对其它子树的答案的影响。

这道题就动态点分呗。

先建出分治结构,然后每个分治的子结构开一个线段树维护不同深度的答案。

为了去重,每个分治结构的每个子树还要开一个线段树,表示在这个子树内要去掉的答案。

询问和修改直接从分治结构最底层向上爬,修改或者查询线段树上的值就行了。

复杂度nlog^2n

#include<iostream>
#include<cstdio>
#define INF 2000000000
#define MN 100000
#define MD 18
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
bool b[MN+5];
int n,m,head[MN+5],cnt=0,mn,rt,tot,dep[MD+5][MN+5],bel[MD+5][MN+5];
int size[MN+5],mx[MN+5],Fa[MD+5][MN+5],Mxdp[MN+5];
struct edge{int to,next;}e[MN*2+5]; 
struct Tree{int l,r,x;}T[20000000];
inline void ins(int f,int t)
{
    e[++cnt]=(edge){t,head[f]};head[f]=cnt;
    e[++cnt]=(edge){f,head[t]};head[t]=cnt;
};

void GetRt(int x,int fa)
{
    size[x]=1;mx[x]=0;
    for(int i=head[x];i;i=e[i].next)
        if(!b[e[i].to]&&e[i].to!=fa)
        {
            GetRt(e[i].to,x);
            size[x]+=size[e[i].to];
            mx[x]=max(mx[x],size[e[i].to]);
        }    
    int Sz=max(tot-size[x],mx[x]);
    if(Sz<mn) mn=Sz,rt=x;
}

void Dfs(int x,int fa,int Dep)
{
    ++tot;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=fa&&!b[e[i].to])
        {
            bel[Dep][e[i].to]=bel[Dep][x];
            dep[Dep][e[i].to]=dep[Dep][x]+1;    
            Dfs(e[i].to,x,Dep);
        }
}

void Solve(int x,int Dp)
{
    b[x]=1;bel[Dp][x]=++cnt;Mxdp[x]=Dp;dep[Dp][x]=1;
    for(int i=head[x];i;i=e[i].next)    
        if(!b[e[i].to])
        {
            tot=0;dep[Dp][e[i].to]=2;
            bel[Dp][e[i].to]=++cnt;
            Dfs(e[i].to,x,Dp);
            size[e[i].to]=tot;    
        }
    for(int i=head[x];i;i=e[i].next)
        if(!b[e[i].to])
        {
            tot=size[e[i].to];mn=INF;
            GetRt(e[i].to,x);    
            Fa[Dp+1][rt]=x;
            Solve(rt,Dp+1);
        }
}

int Query(int x,int v,int lt,int rt)
{
    if(!x) return 0;
    if(lt==rt) return T[x].x;
    int mid=lt+rt>>1,res;
    if(v<=mid) res=Query(T[x].l,v,lt,mid);
    else       res=Query(T[x].r,v,mid+1,rt);
    return res+T[x].x;
}
inline int node(int x){return x?x:++cnt;}
void Modify(int x,int l,int r,int lt,int rt,int v)
{
    if(l==lt&&r==rt) {T[x].x+=v;return;}
    int mid=lt+rt>>1;
    if(r<=mid) Modify(T[x].l=node(T[x].l),l,r,lt,mid,v);
    else if(l>mid) Modify(T[x].r=node(T[x].r),l,r,mid+1,rt,v);
    else Modify(T[x].l=node(T[x].l),l,mid,lt,mid,v),
         Modify(T[x].r=node(T[x].r),mid+1,r,mid+1,rt,v);    
}
char op[5];
int main()
{
    n=read();m=read();
    for(int i=1;i<n;++i) ins(read(),read());
    cnt=0;mn=INF;tot=n;GetRt(1,0);Solve(rt,1);
    for(int ii=1;ii<=m;++ii)
    {
        scanf("%s",op+1);    
        if(op[1]=='Q')
        {
            int x=read(),sum=0;
            for(int j=Mxdp[x],k=x;j;k=Fa[j--][k])
            {
                sum+=Query(bel[j][k],dep[j][x],1,MN);
                if(j!=Mxdp[x])
                    sum-=Query(bel[j][x],dep[j][x],1,MN);
            }
            printf("%d\n",sum);
        }
        else
        {
            int x=read(),d=read(),w=read();
            for(int j=Mxdp[x],k=x;j;k=Fa[j--][k])
                if(d-dep[j][x]+2>=1)
                {
                    Modify(bel[j][k],1,d-dep[j][x]+2,1,MN,w);
                    if(Mxdp[x]!=j)
                        Modify(bel[j][x],1,d-dep[j][x]+2,1,MN,w);
                }    
        }
    }
    return 0;
}
posted @ 2017-06-05 16:36  FallDream  阅读(223)  评论(0编辑  收藏  举报