[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\n",vis[1]&INF);
            for(int i=1;i<=K;i++) set_vis(u[i],v[i],0);
        }
    }
    return 0;
}
posted @ 2018-08-29 11:38  wxjor  阅读(222)  评论(0编辑  收藏  举报