zoukankan      html  css  js  c++  java
  • BZOJ_3589_动态树_容斥原理+树链剖分

    BZOJ_3589_动态树_容斥原理+树链剖分

    题意:

    维护一棵树,支持1.子树内点权加上一个数  2.给出k条链,求路径上的点权和(重复的计算一次) (k<=5)

    分析:

    可以用树剖+线段树解决第一个操作

    然后我们发现k非常小,可以二进制枚举

    那就容斥一下转化成求几条链的交

    链交求法:链顶是两条链顶深度大的那个,链底是两个链底的lca

    如果链底深度小于链顶,就说明两条链没有交集

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 200050
    #define LL long long
    #define ls p<<1
    #define rs p<<1|1
    int head[N],to[N<<1],nxt[N<<1],cnt,n,q,xx[10],yy[10];
    int fa[N],dep[N],top[N],siz[N],son[N],idx[N],tot,k;
    int _count[100],strtop[10],strbot[10];
    LL mod=2147483648ll;
    LL t[N<<2],add[N<<2];
    inline void adde(int u,int v){
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
    }
    void dfs1(int x,int y){
        int i;
        fa[x]=y;dep[x]=y+1;
        siz[x]=1;
        for(i=head[x];i;i=nxt[i]){
            if(to[i]!=y){
                dfs1(to[i],x);
                siz[x]+=siz[to[i]];
                if(siz[to[i]]>siz[son[x]])son[x]=to[i];
            }
        }
    }
    void dfs2(int x,int t){
        top[x]=t;idx[x]=++tot;
        int i;
        if(son[x]) dfs2(son[x],t);
        for(i=head[x];i;i=nxt[i]){
            if(to[i]!=fa[x]&&to[i]!=son[x]){
                dfs2(to[i],to[i]);
            }
        }
    }
    void pud(int l,int r,int p){
        if(add[p]==0)return ;
        add[ls]+=add[p];
        add[ls]%=mod;
        add[rs]+=add[p];
        add[rs]%=mod;
        int mid=l+r>>1;
        t[ls]+=add[p]*(mid-l+1);
        t[ls]%=mod;
        t[rs]+=add[p]*(r-mid);
        t[rs]%=mod;
        add[p]=0;
    }
    void update(int l,int r,int x,int y,int c,int p){
        if(x<=l&&y>=r){
            t[p]+=1ll*c*(r-l+1);
            add[p]+=c;
            t[p]%=mod;
            add[p]%=mod;
            return ;
        }
        pud(l,r,p);
        int mid=l+r>>1;
        if(x<=mid)update(l,mid,x,y,c,ls);
        if(y>mid)update(mid+1,r,x,y,c,rs);
        t[p]=t[ls]+t[rs];
        t[p]%=mod;
    }
    LL query(int l,int r,int x,int y,int p){
        if(x<=l&&y>=r) return t[p];
        int mid=l+r>>1;
        LL re=0;
        pud(l,r,p);
        t[p]=t[ls]+t[rs];
        t[p]%=mod;
        if(x<=mid)re=(re+query(l,mid,x,y,ls))%mod;
        if(y>mid)re=(re+query(mid+1,r,x,y,rs))%mod;
        return re%mod;
    }
    LL ask(int x,int y){
        LL re=0;
        while(top[x]!=top[y]){
            if(dep[top[x]]>dep[top[y]])swap(x,y);
            re+=query(1,n,idx[top[y]],idx[y],1);
            re%=mod;
            y=fa[top[y]];
        }
        if(dep[x]<dep[y])swap(x,y);
        return (re+query(1,n,idx[y],idx[x],1))%mod;
    }
    void fix(int x,int c){
        update(1,n,idx[x],idx[x]+siz[x]-1,c,1);
    }
    int lca(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]>dep[top[y]])swap(x,y);
            y=fa[top[y]];
        }
        return dep[x]<dep[y]?x:y;
    }
    void solve(){
        int mask=(1<<k)-1;
        int i,flg,j;
        LL ans=0;
        for(i=1;i<=k;i++){
            if(dep[xx[i]]>dep[yy[i]])swap(xx[i],yy[i]);
            strtop[i]=xx[i];strbot[i]=yy[i];
        }
        for(i=1;i<=mask;i++){
            if((_count[i]&1))flg=1;
            else flg=-1;
            int no_jiao=0;
            int top_a=0,bot_a=0;
            for(j=1;j<=k;j++){
                if(i&(1<<j-1)){
                    if(!top_a){
                        top_a=strtop[j];
                        bot_a=strbot[j];
                    }
                    else {
                        bot_a=lca(bot_a,strbot[j]);
                        if(dep[top_a]<dep[strtop[j]]){
                            top_a=strtop[j];
                        }
                        if(dep[top_a]>dep[bot_a])no_jiao=1;
                    }
                }
            }
            if(no_jiao)continue;
            ans+=flg*ask(top_a,bot_a);
            ans=(ans+mod)%mod;
        }
        printf("%lld
    ",ans);
    }
    int main(){
        scanf("%d",&n);
        int i,x,y,opt,j;
        for(i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            adde(x,y);adde(y,x);
        }
        dfs1(1,0);
        dfs2(1,1);
        for(i=1;i<=32;i++){
            _count[i]=_count[i>>1]+(i&1);
        }
        scanf("%d",&q);
        while(q--){
            scanf("%d",&opt);
            if(opt){
                scanf("%d",&k);
                for(j=1;j<=k;j++){
                    scanf("%d%d",&xx[j],&yy[j]);
                }
                solve();
            }else{
                scanf("%d%d",&x,&y);
                fix(x,y);
            }
        }
    }
    
  • 相关阅读:
    Spring警告: Could not load driverClass com.mysql.jdbc.Driver(待解决)
    马士兵_JAVA自学之路(为那些目标模糊的码农们)
    Spring报错:java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist
    安装spring报错:Cannot complete the install because of a conflicting dependency.
    MYSQL外键(Foreign Key)的使用
    MongoDB(Roboit3T)中导出集合数据
    Express安装
    ES6学习
    C#中添加log4net(日志文件)
    登录MES系统后台服务的操作
  • 原文地址:https://www.cnblogs.com/suika/p/8542490.html
Copyright © 2011-2022 走看看