BZOJ4372烁烁的游戏

【题意】

P6329 【模板】点分树 | 震波 十分相似,给一个树,要求你支持如下操作

1.查询某个点权 2.修改到某个点距离小于等于k的点

【分析】

具体的方法就看上一道题目吧,这个只需要把变成区间修改单点查询即可,注意打好永久化标记即可

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int head[maxn],tot,q,n;
struct edge
{
    int to,nxt;
}e[maxn<<1];
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
void add(int x,int y)
{
    e[++tot].to=y; e[tot].nxt=head[x]; head[x]=tot;
}
//点分树部分开始___________________________________________________________
int vis[maxn],size,gsiz,siz[maxn],root;
int fa[maxn];
void findrt(int u,int fa)
{
    siz[u]=1;
    int maxsiz=0;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(vis[to] || to==fa) continue;
        findrt(to,u);
        siz[u]+=siz[to];
        maxsiz=max(maxsiz,siz[to]);
    }
    maxsiz=max(maxsiz,size-siz[u]);
    if(maxsiz<gsiz)
    {
        gsiz=maxsiz;
        root=u;
    }
}
void solve(int u)
{
    vis[u]=1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(vis[to]) continue;
        size=gsiz=siz[to];
        findrt(to,0);
        fa[root]=u;
        solve(root);
    }
}
//点分树部分开始___________________________________________________________

//ST表O(1)求LCA部分开始____________________________________________________
int st[maxn<<1][20],dfn[maxn],cs,dfstime,lg[maxn<<1];
int dep[maxn];
void dfs(int u,int fa)
{
    dfn[u]=++dfstime;
    st[dfn[u]][0]=dep[u];
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dep[to]=dep[u]+1;
        dfs(to,u);
        st[++dfstime][0]=dep[u];
    }    
}
void lca_init()
{
    lg[0]=-1;
    for(int i=1;i<=n*2;i++) lg[i]=lg[i>>1]+1;
    while((1<<(cs+1))<=n*2) cs++;
    for(int j=1;j<=cs;++j)
        for(int i=1;i+(1<<j)-1<=(n<<1);++i)
            st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int lcadis(int x,int y)
{
    if(dfn[x]>dfn[y]) swap(x,y);
    int i=lg[dfn[y]-dfn[x]+1];
    return min(st[dfn[x]][i],st[dfn[y]-(1<<i)+1][i]);
}
int calcdis(int x,int y)
{
    return dep[x]+dep[y]-2*lcadis(x,y);
}
//ST表O(1)求LCA部分结束____________________________________________________ 

//线段树部分开始___________________________________________________________
struct seg
{
    int l,r,sum;
}tr[maxn*20*8];
int segtot,rt[maxn<<1];
int Query(int now,int l,int r,int pos)
{
    if(!now) return 0;
    if(l==r) return tr[now].sum;
    int mid=(l+r)>>1;
    if(pos<=mid) return Query(tr[now].l,l,mid,pos)+tr[now].sum;
    else return Query(tr[now].r,mid+1,r,pos)+tr[now].sum;
}
void update(int &now,int l,int r,int L,int R,int val)
{
    if(!now) now=++segtot;
    if(L>r || l>R) return;
    if(l>=L && r<=R)
    {
        tr[now].sum+=val;
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid) update(tr[now].l,l,mid,L,R,val);
    if(mid<R) update(tr[now].r,mid+1,r,L,R,val);
}
//线段树部分结束___________________________________________________________

//操作部分开始_____________________________________________________________
void modify(int x,int y,int z)
{
    int u;
    update(rt[x],0,n,0,y,z);
    for(u=x;fa[u];u=fa[u])
    {
        int d=calcdis(fa[u],x);
        if(d>y) continue;
        update(rt[fa[u]],0,n,0,y-d,z);
        update(rt[n+u],0,n,0,y-d,z);
    }
}
int query(int x)
{
    int res=0;
    res+=Query(rt[x],0,n,0);
    for(int u=x;fa[u];u=fa[u])
    {
        int d=calcdis(fa[u],x);
        res+=Query(rt[fa[u]],0,n,d);
        res-=Query(rt[u+n],0,n,d);
    }
    return res;
}
//操作部分结束_____________________________________________________________ 
int main()
{
    scanf("%d%d",&n,&q);
    int x,y,z;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    dfs(1,0); lca_init();
    size=gsiz=n; findrt(1,0);
    solve(root);
    char op[3];
    for(int i=1;i<=q;i++)
    {
        scanf("%s",op);
        if(op[0]=='M')
        {
            scanf("%d%d%d",&x,&y,&z);
            modify(x,y,z);
        }
        else
        {
            scanf("%d",&x);
            printf("%d\n",query(x));
        }
    }
    return 0;
}

 

posted @ 2021-05-20 22:26  andyc_03  阅读(52)  评论(0)    收藏  举报