zoukankan      html  css  js  c++  java
  • 【bzoj3589】动态树【树链剖分】【线段树】

    题目链接
    题解
    首先,第一个操作就是子树加,直接线段树对应dfn序区间加即可。
    第二个操作,我写了个奇怪的东西,单次查询大概是两个log的,常数大上天……其实,这个过程类似于线段覆盖。我们可以维护
    setv:该区间是否被完全覆盖
    tot:该区间被覆盖的个数。
    然后我们在线段树上,对着没覆盖完的节点走一遍。先找到查询的区间,然后遇到完全覆盖的节点和叶子节点返回,完全未覆盖的区间更新答案和标记再返回,否则往左右儿子走。最后把变了的节点复原。细节见代码。
    然后就A了。
    代码

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=200005;
    int n,m,op,k,u,v,cnt,ans,head[N],to[N*2],nxt[N*2];
    int idx,fa[N],dep[N],siz[N],son[N],dfn[N],pos[N],top[N];
    int sumv[N*4],setv[N*4],tot[N*4],tag1[N*4],tag2[N*4],fix[N*8];
    void adde(int u,int v){
        to[++cnt]=v;
        nxt[cnt]=head[u];
        head[u]=cnt;
    }
    void dfs(int u){
        siz[u]=1;
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=fa[u]){
                fa[v]=u;
                dep[v]=dep[u]+1;
                dfs(v);
                siz[u]+=siz[v];
                if(!son[u]||siz[son[u]]<siz[v]){
                    son[u]=v;
                }
            }
        }
    }
    void dfs(int u,int tp){
        dfn[u]=++idx;
        pos[idx]=u;
        top[u]=tp;
        if(son[u]){
            dfs(son[u],tp);
        }
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=fa[u]&&v!=son[u]){
                dfs(v,v);
            }
        }
    }
    void pushdown(int o,int l,int r){
        int mid=(l+r)/2;
        if(tag1[o]){
            tag1[o*2]+=tag1[o];
            tag1[o*2+1]+=tag1[o];
            sumv[o*2]+=tag1[o]*(mid-l+1);
            sumv[o*2+1]+=tag1[o]*(r-mid);
            tag1[o]=0;
        }
        if(tag2[o]){
            tag2[o*2]=tag2[o*2+1]=setv[o*2]=setv[o*2+1]=1;
            tot[o*2]=mid-l+1;
            tot[o*2+1]=r-mid;
            fix[++fix[0]]=o*2;
            fix[++fix[0]]=o*2+1;
            tag2[o]=0;
        }
    }
    void update(int o,int l,int r,int L,int R,int v){
        if(L<=l&&R>=r){
            sumv[o]+=v*(r-l+1);
            tag1[o]+=v;
            return;
        }
        pushdown(o,l,r);
        int mid=(l+r)/2;
        if(L<=mid){
            update(o*2,l,mid,L,R,v);
        }
        if(R>mid){
            update(o*2+1,mid+1,r,L,R,v);
        }
        sumv[o]=sumv[o*2]+sumv[o*2+1];
    }
    void query(int o,int l,int r,int L,int R){
        fix[++fix[0]]=o;
        if(L<=l&&R>=r){
            if(!tot[o]){
                ans+=sumv[o];
                setv[o]=tag2[o]=1;
                tot[o]=r-l+1;
                fix[++fix[0]]=o;
                return;
            }
            if(l==r||setv[o]){
                return;
            }
            pushdown(o,l,r);
            int mid=(l+r)/2;
            if(tot[o*2]<mid-l+1){
                query(o*2,l,mid,L,R);
            }
            if(tot[o*2+1]<r-mid){
                query(o*2+1,mid+1,r,L,R);
            }
            setv[o]=setv[o*2]&&setv[o*2+1];
            tot[o]=tot[o*2]+tot[o*2+1];
            return;
        }
        pushdown(o,l,r);
        int mid=(l+r)/2;
        if(L<=mid){
            query(o*2,l,mid,L,R);
        }
        if(R>mid){
            query(o*2+1,mid+1,r,L,R);
        }
        setv[o]=setv[o*2]&&setv[o*2+1];
        tot[o]=tot[o*2]+tot[o*2+1];
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            adde(u,v);
            adde(v,u);
        }
        dfs(1);
        dfs(1,1);
        scanf("%d",&m);
        while(m--){
            scanf("%d",&op);
            if(!op){
                scanf("%d%d",&u,&v);
                update(1,1,n,dfn[u],dfn[u]+siz[u]-1,v);
            }else{
                scanf("%d",&k);
                ans=0;
                while(k--){
                    scanf("%d%d",&u,&v);
                    while(top[u]!=top[v]){
                        if(dep[top[u]]<dep[top[v]]){
                            swap(u,v);
                        }
                        query(1,1,n,dfn[top[u]],dfn[u]);
                        u=fa[top[u]];
                    }
                    if(dep[u]>dep[v]){
                        swap(u,v);
                    }
                    query(1,1,n,dfn[u],dfn[v]);
                }
                printf("%d
    ",ans&2147483647);
                for(int i=1;i<=fix[0];i++){
                    setv[fix[i]]=tag2[fix[i]]=tot[fix[i]]=0;
                }
                fix[0]=0;
            }
        }
        return 0;
    }
  • 相关阅读:
    【题解】P2262 [HNOI2004]FTP服务器
    关于大模拟
    CodeForces 666E Forensic Examination
    Bzoj3233 [Ahoi2013]找硬币
    Bzoj4350 括号序列再战猪猪侠
    UOJ#31 【UR #2】猪猪侠再战括号序列
    UOJ#21 【UR #1】缩进优化
    51nod1667 概率好题
    [CodeChef
    51nod1245 Binomial Coefficients Revenge
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476852.html
Copyright © 2011-2022 走看看