【BZOJ4372】烁烁的游戏 动态树分治

讲道理我第一次看到动态树分治以为和那个动态树LCT有关QAQ

然而正确的读法是【动态(树分治)】

这就很尴尬了。

题目大意就是给定一棵树,每个点初始权值是0,维护两个操作,一是将和某一个点距离不超过d的点的权值都加上v,二是查询某两个点之间的权值。

首先用点分治建出新的树结构,利用标记永久化的思想为每个点建立一棵线段树记录距离这个点距离为d的点的权值之和,统计的时候再求一下和即可。

唯一要注意的是,为了防止两个节点算重要给每个儿子节点多开开一棵线段树。

/**************************************************************
    Problem: 4372
    User: RicardoWang
    Language: C++
    Result: Accepted
    Time:22804 ms
    Memory:264684 kb
****************************************************************/
 
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
void _read(int &x)
{
    x=0; char ch=getchar(); bool flag=false;
    while(ch<'0' || ch>'9'){if(ch=='-')flag=true; ch=getchar();}
    while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();} if(flag)x=-x; return ;
}
#define MAXN 200005
struct edge
{
    int to,next;
}e[MAXN*2];
int n,m,edge_ct,head[MAXN];
bool del[MAXN];
void add(int x,int y)
{
    e[++edge_ct]=(edge){y,head[x]}; head[x]=edge_ct;
    e[++edge_ct]=(edge){x,head[y]}; head[y]=edge_ct; return ;
}
int root,sz[MAXN],c[MAXN],f[MAXN],d[MAXN],fb[MAXN][20];
void getroot(int x,int fa,int sum)
{
    sz[x]=1; c[x]=0;
    for(int id=head[x];id;id=e[id].next)
    {
        if(e[id].to==fa || del[e[id].to])continue;
        getroot(e[id].to,x,sum); sz[x]+=sz[e[id].to]; c[x]=max(c[x],sz[e[id].to]);
    }
    c[x]=max(sum-sz[x],c[x]);
    if(c[x]<c[root])root=x;
    return ;
}
void _DFS(int now,int fa)
{
    sz[now]=1;
    for(int id=head[now];id;id=e[id].next)
    {
        if(del[e[id].to] || e[id].to==fa)continue;
        _DFS(e[id].to,now);
        sz[now]+=sz[e[id].to];
    }
    return ;
}
void _build(int now,int fa,int sum)
{
    root=0; getroot(now,0,sum);
    int nowroot=root;
    del[nowroot]=true; f[nowroot]=fa;
    _DFS(nowroot,0);
    for(int id=head[nowroot];id;id=e[id].next)
    {
        if(del[e[id].to])continue;
        _build(e[id].to,nowroot,sz[e[id].to]);
    }
    return ;
}
void DFS_0(int now,int fa)
{
    for(int id=head[now];id;id=e[id].next)
    {
        if(e[id].to==fa)continue;
        d[e[id].to]=d[now]+1; f[e[id].to]=now;
        DFS_0(e[id].to,now);
    }
    return ;
}
void makesa()
{
    for(int i=1;i<=n;i++)fb[i][0]=f[i];
    for(int k=1;k<=17;k++)
    {
        for(int i=1;i<=n;i++)fb[i][k]=fb[fb[i][k-1]][k-1];
    }
    return ;
}
int LCA(int x,int y)
{
    if(d[x]<d[y])swap(x,y);
    for(int k=17;k>=0;k--)if(d[x]-d[y]>=(1<<k))
    {
        x=fb[x][k];
    }
    if(x==y)return x;
    for(int k=17;k>=0;k--)if(fb[x][k]!=fb[y][k])
    {
        x=fb[x][k]; y=fb[y][k];
    }
    return fb[x][0];
}
int getdis(int x,int y)
{
    return d[x]+d[y]-2*d[LCA(x,y)];
}
void Init()
{
    _read(n); _read(m);
    int x,y;
    for(int i=1;i<n;i++){_read(x); _read(y); add(x,y);}
    DFS_0(1,0);makesa();
    memset(f,0,sizeof(f));
    c[0]=n+1;_build(1,0,n);
    return ;
}
int np,rt1[MAXN],rt2[MAXN],chi[100*MAXN][2],w[100*MAXN];
void update(int &now,int L,int R,int x,int y,int de)
{
    if(!now){now=++np; w[now]=0;}
    if(x<=L && R<=y){w[now]+=de; return ;}
    int m=(L+R)>>1;
    if(x<=m)update(chi[now][0],L,m,x,y,de);
    if(y>m)update(chi[now][1],m+1,R,x,y,de);
    return ;
}
int query(int &now,int L,int R,int x)
{
    int ans=w[now];
    if(!now || L==R)return w[now];
    int m=(L+R)>>1;
    return x<=m ? ans+query(chi[now][0],L,m,x): ans+query(chi[now][1],m+1,R,x);
}
void MM(int x,int y,int z)
{
    int dis;
    update(rt1[x],0,n,0,y,z);
    for(int i=x;f[i];i=f[i])
    {
        dis=getdis(x,f[i]);if(dis>y)continue;
        update(rt1[f[i]],0,n,0,y-dis,z);
        update(rt2[i],0,n,0,y-dis,z);
    }
    return ;
}
int QQ(int now)
{
    int ans=0,dis;
    ans+=query(rt1[now],0,n,0);
    for(int i=now;f[i];i=f[i])
    {
        dis=getdis(f[i],now);
        ans+=query(rt1[f[i]],0,n,dis)-query(rt2[i],0,n,dis);
    }
    return ans;
}
void work()
{
    char op;
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        op=getchar(); while(op!='M' && op!='Q')op=getchar();
        if(op=='Q')
        {
            _read(x); 
            printf("%d\n",QQ(x));
        }
        else
        {
            _read(x); _read(y); _read(z); MM(x,y,z);
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    Init();
    work();
    return 0;
}


发布了61 篇原创文章 · 获赞 1 · 访问量 3万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览