zoukankan      html  css  js  c++  java
  • [BZOJ3589] 动态树

    [BZOJ3589] 动态树

    Description

    别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子.
    事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次.

    Input

    第一行一个整数n(1<=n<=200,000), 即节点数.
    接下来n-1行, 每行两个数字u, v. 表示果子u和果子v之间有一条直接的边. 节点从1开始编号.
    在接下来一个整数nQ(1<=nQ<=200,000), 表示事件.
    最后nQ行, 每行开头要么是0, 要么是1.
    如果是0, 表示这个事件是事件0. 这行接下来的2个整数u, delta表示以u为根的子树中的每个节点长出了delta个果子.
    如果是1, 表示这个事件是事件1. 这行接下来一个整数K(1<=K<=5), 表示这次询问涉及K个树枝. 接下来K对整数u_k, v_k, 每个树枝从节点u_k到节点v_k. 由于果子数可能非常多, 请输出这个数模2^31的结果.

    Output

    对于每个事件1, 输出询问的果子数.

    Sample Input

    5
    1 2
    2 3
    2 4
    1 5
    3
    0 1 1
    0 2 3
    1 2 3 1 1 4

    Sample Output

    13

    试题分析

    懒得写容斥?线段树上标记大法好。
    直接对于每个询问在线段树上再维护一个数组,然后照样update,最后再来一遍清空即可。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
     
    using namespace std;
    #define LL long long
     
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    #define INF 0x7fffffff
    const int MAXN = 400010;
     
    int dep[MAXN+1],sz[MAXN+1],Hvs[MAXN+1],top[MAXN+1];
    int fa[MAXN+1]; int Root[MAXN<<1],Next[MAXN<<1],Node[MAXN<<1],cnt;
    int tr[MAXN<<2]; int vis[MAXN<<2]; int Don[MAXN+1];
    int dfn[MAXN+1]; int N,M; int tim; int R[MAXN+1];
    int col[MAXN<<2];
     
    inline void insert(int u,int v){
        Node[++cnt]=v; Next[cnt]=Root[u]; Root[u]=cnt; return ;
    }
     
    inline void dfs1(int k,int Fa){
        fa[k]=Fa; sz[k]=1; dep[k]=dep[Fa]+1;
        for(int x=Root[k];x;x=Next[x]){
            int v=Node[x]; if(v==Fa) continue;
            dfs1(v,k); sz[k]+=sz[v];
            if(!Hvs[k]||sz[Hvs[k]]<sz[v]) Hvs[k]=v;
        } return ;
    }
    inline void dfs2(int k,int Tp){
        top[k]=Tp; dfn[k]=++tim; Don[tim]=k;
        if(Hvs[k]) dfs2(Hvs[k],Tp);
        for(int x=Root[k];x;x=Next[x]){
            int v=Node[x]; if(v==fa[k]||v==Hvs[k]) continue;
            dfs2(v,v);
        } R[k]=tim; return ;
    }
    inline void tage_lazy(int rt,int l,int r){
        if(col[rt]){
            int mid=(l+r)>>1;
            col[rt<<1]+=col[rt]; col[rt<<1|1]+=col[rt];
            tr[rt<<1]+=(mid-l+1)*col[rt]; tr[rt<<1|1]+=(r-mid)*col[rt];
            col[rt]=0;
        }
    }
    inline void Add(int rt,int l,int r,int L,int R,int x){
        if(L<=l&&R>=r) {tr[rt]+=x*(r-l+1); col[rt]+=x; return ;} tage_lazy(rt,l,r);
        int mid=(l+r)>>1; if(L<=mid) Add(rt<<1,l,mid,L,R,x); 
        if(R>mid) Add(rt<<1|1,mid+1,r,L,R,x);
        tr[rt]=tr[rt<<1]+tr[rt<<1|1]; return ;
    }
    int u[31],v[31];
    int ans;
    inline void Query(int rt,int l,int r,int L,int R){
        //cout<<vis[rt]<<":"<<l<<" "<<r<<" "<<tr[rt]<<" "<<L<<" "<<R<<endl;
        if(L<=l&&R>=r){vis[rt]=tr[rt]; return ;} tage_lazy(rt,l,r);
        int mid=(l+r)>>1; if(L<=mid) Query(rt<<1,l,mid,L,R);
        if(R>mid) Query(rt<<1|1,mid+1,r,L,R); //if(!vis[rt]) vis[rt]=((vis[rt<<1]|vis[rt<<1|1])?2:0);
        if(vis[rt]!=tr[rt]) vis[rt]=vis[rt<<1]+vis[rt<<1|1];
        return ;
    }
    inline void Clear(int rt,int l,int r,int L,int R){
        vis[rt]=0; if(L<=l&&R>=r) return ; int mid=(l+r)>>1; tage_lazy(rt,l,r);
        if(L<=mid) Clear(rt<<1,l,mid,L,R);
        if(R>mid) Clear(rt<<1|1,mid+1,r,L,R); return ;
    }
    inline void set_vis(int x,int y,int opr){
        int fx=top[x],fy=top[y];
        while(fx!=fy){
            if(dep[x]>dep[y]) {
                if(opr==1) Query(1,1,N,dfn[fx],dfn[x]);
                else Clear(1,1,N,dfn[fx],dfn[x]);
                x=fa[fx];
            }
            else {
                if(opr==1) Query(1,1,N,dfn[fy],dfn[y]);
                else Clear(1,1,N,dfn[fy],dfn[y]);
                y=fa[fy];
            } fx=top[x],fy=top[y];
        } if(dfn[x]>dfn[y]) swap(x,y);
        if(opr==1) Query(1,1,N,dfn[x],dfn[y]);
        else Clear(1,1,N,dfn[x],dfn[y]); return ;
    }
     
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        N=read();
        for(int i=1;i<N;i++){
            int u=read(),v=read();
            insert(u,v); insert(v,u);
        } dfs1(1,0); dfs2(1,1);
        int Q=read();
        while(Q--){
            int opr=read();
            if(!opr){
                int k=read(),x=read();
                Add(1,1,N,dfn[k],R[k],x);
                //cout<<dfn[k]<<endl;
            }
            else{
                int K=read(); //LL ans=0;
                for(int i=1;i<=K;i++){
                    u[i]=read(),v[i]=read();
                    set_vis(u[i],v[i],1);
                }printf("%d
    ",vis[1]&INF);
                for(int i=1;i<=K;i++) set_vis(u[i],v[i],0);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    linux 命令学习
    反编译学习一:Mac下使用dex2jar
    如何删除你的MacOS上的旧版本Java
    使用screen 遇到的多窗口
    dede简略标题调用标签
    JQ实现导航滚动到指定位置变色,并置顶
    JQ实现当前页面导航加效果(栏目页有效)
    wordpress首页调用指定分类下的文章
    作业1#python用列表实现多用户登录,并有三次机会
    python数据类型之间的转换
  • 原文地址:https://www.cnblogs.com/wxjor/p/9553376.html
Copyright © 2011-2022 走看看