zoukankan      html  css  js  c++  java
  • [BZOJ4372]烁烁的游戏

    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不一定为正整数,因为烁烁可能把皮皮鼠吓傻了。

    链剖$LCA$打挂调一上午身败名裂

    其实这道题的思路根震波那道题是很相似的,建立点分树然后用线段树维护

    不过这里是区间修改和单点查询,而那道是单点修改区间查询

    维护两颗线段树分别表示点分树某重心子树内到它的距离等于$d$的点和子树内到他父亲距离等于$d$的点

    然后查询的时候跳点分树$fa$,和之前的点容斥后统计答案即可

    这样为什么是对的,因为原树上任意两点经过的第一个重心为他们在点分树上的$LCA$

    于是如果一个点$y$的修改能对$x$产生影响,只有在他们的$LCA$处才会对答案产生贡献

    $LCA$再往上会被它的儿子容斥掉

    解释得不是很清楚自己意会吧

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define M 100010
    #define ls ch[node][0]
    #define rs ch[node][1]
    using namespace std;
    int read() {
        char ch=getchar();int x=0;
        while(ch>'9'||ch<'0') ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    int n,m,num,cnt,root,S;
    int sz[M],size[M],top[M],fa[M],deep[M],son[M],head[M],maxn[M],f[M];
    int rt1[M],rt2[M],val[M<<8],ch[M<<8][2];bool vis[M];
    struct point{int next,to;}e[M<<1];
    void add(int from,int to) {
        e[++num].next=head[from];
        e[num].to=to;
        head[from]=num;
    }
    void dfs1(int x) {
        sz[x]=1;deep[x]=deep[fa[x]]+1;
        for(int i=head[x];i;i=e[i].next) {
            int to=e[i].to;
            if(fa[x]==to) continue;
            fa[to]=x,dfs1(to),sz[x]+=sz[to];
            if(sz[to]>sz[son[x]]) son[x]=to;
        }
    }
    void dfs2(int x,int tp) {
        top[x]=tp;
        if(son[x]) dfs2(son[x],tp);
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=son[x]&&e[i].to!=fa[x])
                dfs2(e[i].to,e[i].to);
    }
    int lca(int x,int y) {
        while(top[x]!=top[y]) {
            if(deep[top[x]]<deep[top[y]]) swap(x,y);
            x=fa[top[x]];
        }
        return deep[x]>deep[y]?y:x;
    }
    int dis(int x,int y) {
        return deep[x]+deep[y]-2*deep[lca(x,y)];
    }
    void getroot(int x,int fa) {
        size[x]=1;maxn[x]=0;
        for(int i=head[x];i;i=e[i].next) {
            int to=e[i].to;
            if(to==fa||vis[to]) continue;
            getroot(to,x);
            size[x]+=size[to];
            maxn[x]=max(maxn[x],size[to]);
        }
        maxn[x]=max(maxn[x],S-size[x]);
        if(maxn[x]<maxn[root]) root=x;
    }
    void solve(int x,int fa) {
        vis[x]=true;f[x]=fa;
        for(int i=head[x];i;i=e[i].next) {
            int to=e[i].to;
            if(vis[to]) continue;
            root=0,S=size[to],getroot(to,0);
            solve(root,x);
        }
    }
    void change(int &node,int l,int r,int l1,int r1,int v) {
        if(!node) node=++cnt;
        if(l1<=l&&r1>=r) {
            val[node]+=v;return;
        }
        int mid=(l+r)/2;
        if(l1<=mid) change(ls,l,mid,l1,r1,v);
        if(r1>mid) change(rs,mid+1,r,l1,r1,v);
    }
    int query(int node,int l,int r,int x) {
        if(!node) return 0;
        if(l==r) return val[node];
        int mid=(l+r)/2;
        if(x<=mid) return val[node]+query(ls,l,mid,x);
        else return val[node]+query(rs,mid+1,r,x);
    }
    void update(int x,int d,int v) {
        change(rt1[x],0,n,0,d,v);
        for(int i=x;f[i];i=f[i]) {
            int dt=dis(x,f[i]);
            if(dt>d) continue;
            change(rt1[f[i]],0,n,0,d-dt,v);
            change(rt2[i],0,n,0,d-dt,v);
        }
    }
    int ask(int x) {
        int res=query(rt1[x],0,n,0);
        for(int i=x;f[i];i=f[i]) {
            int dt=dis(x,f[i]);
            res+=query(rt1[f[i]],0,n,dt)-query(rt2[i],0,n,dt);
        }
        return res;
    }
    int main() {
        n=read();m=read();
        for(int i=1;i<n;i++) {
            int u=read(),v=read();
            add(u,v),add(v,u);
        }
        dfs1(1),dfs2(1,1);
        maxn[0]=S=n;
        getroot(1,0),solve(root,0);
        for(int i=1;i<=m;i++) {
            char s[10];scanf("%s",s);
            if(s[0]=='M') {
                int x=read(),d=read(),w=read();
                update(x,d,w);
            }
            else {
                int x=read();
                printf("%d
    ",ask(x));
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    企业如何推行白盒测试
    Java命名规范
    MobileVLC for iphoneos4.3
    用Android NDK编译FFmpeg
    Linux 下Android 开发环境搭建 ---CentOS
    为什么要做白盒测试
    vlc的第三方库contrib的修改之一:live库的修改
    VC命名规范
    POJ 1470 Closest Common Ancestors (LCA入门题)
    HDU 4407 Sum 第37届ACM/ICPC 金华赛区 第1008题 (容斥原理)
  • 原文地址:https://www.cnblogs.com/Slrslr/p/10026148.html
Copyright © 2011-2022 走看看