zoukankan      html  css  js  c++  java
  • A National Pandemic【树链剖分】

    题意

    给出一棵 (n) 个点的树,每个点 (x) 有一个 (f(x)) 值,初始全为 (0)。现在有三种操作共 (m) 次:

    1. 输入:(x,w),选择一个点 (x) ,对于树上的所有点 (y)(f(y)) 将增加 (w-dist(x,y))。其中,(dist(x,y)) 表示 (x)(y) 之间最短路径的边数。
    2. 输入:(x),更新 (f(x))(min(f(x),0))
    3. 输入: (x) ,询问 (f(x))

    (1leq n,m leq 5 imes 10^4,0leq w leq 10000)

    题目链接:https://ac.nowcoder.com/acm/contest/5672/C

    分析

    难点在于操作 (1) 如何实现,每次修改所有点必然不现实,因此,要想办法将影响保存起来,在查询的时候直接处理。

    首先,对于 (w-dist(x,y)),可以写成 ((w-depth[x])-(depth[y])+(2 imes dpeth[lca(x,y)]))。对于其中的 (3) 部分,分别处理。((w-depth[x])) 可以在操作 (1) 的时候,一边操作,一边记录。对于 ((depth[y])) ,只要知道在查询当前点之前进行了多少次操作 (1) ,就可以直接算出。对于 ((2 imes depth[lca(x,y)])),只要在每次操作 (1) 时,将点 (x) 到根节点的路径上所有边的值加 (2) ,在查询的时候,只要从查询点向根节点求出路径上的边的权值和即可。

    对于 (2),将上一次修改为 (0) 的结果记录下来,下次查询的时候减去即可。

    代码

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=5e4+5;
    vector<int>pic[N];
    int fa[N],depth[N],num[N];
    int top[N],dfn[N],sz[N],son[N];
    int tree[N<<2],n,lazy[N<<2];
    void dfs1(int u,int p,int d)
    {
        depth[u]=d;
        fa[u]=p;
        sz[u]=1;
        son[u]=0;
        for(int i=0;i<pic[u].size();i++)
        {
            int v=pic[u][i];
            if(v==p) continue;
            dfs1(v,u,d+1);
            sz[u]+=sz[v];
            if(sz[v]>sz[son[u]])
                son[u]=v;
        }
    }
    void dfs2(int u,int p,int tp,int &cnt)
    {
        top[u]=tp;
        dfn[u]=++cnt;
        if(son[u]==0) return;
        dfs2(son[u],u,tp,cnt);
        for(int i=0;i<pic[u].size();i++)
        {
            int v=pic[u][i];
            if(v==p||v==son[u]) continue;
            dfs2(v,u,v,cnt);
        }
    }
    void pushup(int rt)
    {
        tree[rt]=tree[rt<<1]+tree[rt<<1|1];
    }
    void pushdown(int ln,int rn,int rt)
    {
        if(lazy[rt])
        {
            tree[rt<<1]+=ln*lazy[rt];
            tree[rt<<1|1]+=rn*lazy[rt];
            lazy[rt<<1]+=lazy[rt];
            lazy[rt<<1|1]+=lazy[rt];
            lazy[rt]=0;
        }
    }
    void build(int l,int r,int rt)
    {
        lazy[rt]=0;
        if(l==r)
        {
            tree[rt]=0;
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
        pushup(rt);
    }
    void update(int l,int r,int L,int R,int val,int rt)
    {
        if(L<=l&&r<=R)
        {
            tree[rt]+=val*(r-l+1);
            lazy[rt]+=val;
            return;
        }
        int mid=(l+r)>>1;
        pushdown(mid-l+1,r-mid,rt);
        if(L<=mid) update(l,mid,L,R,val,rt<<1);
        if(R>mid) update(mid+1,r,L,R,val,rt<<1|1);
        pushup(rt);
    }
    int query(int l,int r,int L,int R,int rt)
    {
        if(L<=l&&r<=R)
            return tree[rt];
        int mid=(l+r)>>1,res=0;
        pushdown(mid-l+1,r-mid,rt);
        if(L<=mid) res+=query(l,mid,L,R,rt<<1);
        if(R>mid) res+=query(mid+1,r,L,R,rt<<1|1);
        return res;
    }
    void change(int u,int v,int val)
    {
        while(top[u]!=top[v])
        {
            if(depth[top[u]]<depth[top[v]])
                swap(u,v);
            update(1,n,dfn[top[u]],dfn[u],val,1);
            u=fa[top[u]];
        }
        if(depth[u]<depth[v]) swap(u,v);
        update(1,n,dfn[v],dfn[u],val,1);
    }
    int ask(int u,int v)
    {
        int res=0;
        while(top[u]!=top[v])
        {
            if(depth[top[u]]<depth[top[v]]) swap(u,v);
            res+=query(1,n,dfn[top[u]],dfn[u],1);
            u=fa[top[u]];
        }
        if(depth[u]<depth[v]) swap(u,v);
        res+=query(1,n,dfn[v],dfn[u],1);
        return res;
    }
    int main()
    {
        int T,m;
        scanf("%d",&T);
        while(T--)
        {
            int x,y,cnt=0,sum=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            {
                pic[i].clear();
                num[i]=0;
            }
            for(int i=1;i<n;i++)
            {
                scanf("%d%d",&x,&y);
                pic[x].pb(y);
                pic[y].pb(x);
            }
            dfs1(1,0,0);
            dfs2(1,0,1,cnt);
            build(1,cnt,1);
            int opt,w,cot=0;
            while(m--)
            {
                scanf("%d",&opt);
                if(opt==1)
                {
                    scanf("%d%d",&x,&w);
                    change(1,x,2);
                    change(1,1,-2);
                    cot++;
                    sum+=(w-depth[x]);
                }
                else if(opt==2)
                {
                    scanf("%d",&x);
                    int tmp=sum-depth[x]*cot+ask(1,x)-ask(1,1)-num[x];
                    if(tmp>0) num[x]+=tmp;//记录
                }
                else
                {
                    scanf("%d",&x);
                    int tmp=sum-depth[x]*cot+ask(1,x)-ask(1,1)-num[x];
                    printf("%d
    ",tmp);
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    1. 关于GCD的使用(串并行队列和同步异步函数的问题)
    陌院俅颗难炎先当粮澜
    openresty在centos/redhat6.7上部署
    tomcat 日志那点事
    Redhat6.7 切换Centos yum源
    Quartz corn时间表达式(转)
    Jquery控制滚动Div 滚动条事件
    fastjson排序 Map多层嵌套转换自动排序问题终极解决方案
    Spring 外部注入Bean (JAX-WS)
    SSH,如何恢复通过输入密码的方式来登录服务器
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/13620808.html
Copyright © 2011-2022 走看看