• Codechef Sad Pairs——圆方树+虚树+树上差分


    SADPAIRS

    删点不连通,点双,圆方树 

    非割点:没有影响

    割点:子树DP一下

    有不同颜色,所以建立虚树

    在圆方树上dfs时候

    如果当前点是割点

    1.统计当前颜色虚树上的不连通点对,树形DP即可

    2.统计所有颜色的虚树上的不连通点对。。。。

    一个麻烦事是,虚树上一条边上选择一个原树割点,都会对这个虚树造成相同的影响(两边sz乘积)

    n,m 2e5

    树上差分

    设虚树上,(x,y)的边,x是y的父亲

    原树上,x的位置减去贡献,y的原树father位置加上贡献

    最后dfs扫一遍就行了。

    实际上麻烦事挺多:

    1.不保证连通,所以圆方树森林,虚树森林

    2.LCA可能是多个颜色虚树的节点,dp[x]是累计的

    3.x断线只有的ans:原来本身不连通的+经过x的+x和同种别的颜色 (后面两个都是自己连通块内部)

    错点:

    1.dfn的cmp没有写进sort函数

    2.vis在dfs时候没有赋值导致循环多遍

    3.存在孤立点,不在任意一个DCC中,赋值typ=1的时候,特殊考虑到(其实typ=1没有意义)

    4.统计的是当前连通块当前颜色的数量,所以初值:sz[x]=(co[x]==now)

    5.答案爆int。两块sz相乘也会爆int

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define reg register int
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=4e5+5;
    int n,m;
    int a[N][2];
    int kind;//species
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    int dfn[N],low[N],df,dfn2[N];
    int co[N],b[N],dcc;
    vector<int>mem[N];
    ll preno;
    vector<int>be[N];
    int typ[N];//1:yuan 0:fang
    int sta[N],top;
    void tarjan(int x){
        dfn[x]=low[x]=++df;
        sta[++top]=x;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
                if(low[y]>=dfn[x]){
                    ++dcc;
                    int z;
                    do{
                        z=sta[top];
                        mem[dcc].push_back(z);
                        --top;
                    }while(z!=y);
                    mem[dcc].push_back(x);
                }
            }else low[x]=min(low[x],dfn[y]);
        }
    }
    int belong[N];
    int dep[N],fa[N][20];
    void dfs1(int x,int bl,int d){
        belong[x]=bl;
        dfn[x]=++df;
        dep[x]=d;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!dfn[y]){
                fa[y][0]=x;
                dfs1(y,bl,d+1);
            }
        }
        dfn2[x]=df;
    }
    ll dp[N];
    ll tag[N];
    int vis[N];
    ll sz[N];
    void finsz(int x,int now){
        vis[x]=now+kind;
        sz[x]=(co[x]==now);
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            finsz(y,now);
            sz[x]+=sz[y];
        }
    }
    void dfs2(int x,ll totsz,int now){
    //    cout<<" dfs2 "<<x<<" : "<<totsz<<" "<<now<<endl;
        ll presz=0;
        //dp[x]=0;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            dfs2(y,totsz,now);
            tag[x]-=(totsz-sz[y])*sz[y];
            //cout<<" fa[y][0] "<<fa[y][0]<<endl;
            tag[fa[y][0]]+=(totsz-sz[y])*sz[y];
            dp[x]+=presz*sz[y];
            presz+=sz[y];
        }
        dp[x]+=presz*(totsz-sz[x]);
        if(co[x]==now)dp[x]+=totsz-typ[x];
    }
    ll ans[N];
    
    void sol(int x,int fa){
        vis[x]=1;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            sol(y,x);
            tag[x]+=tag[y];
        }
        //cout<<" x "<<x<<" : "<<preno+dp[x]+tag[x]<<endl;
        if(typ[x]) ans[x]=preno+dp[x]+tag[x];
    }
    bool cmp(int x,int y){
        return dfn[x]<dfn[y];
    }
    int lca(int x,int y){
        if(dep[x]<dep[y]) swap(x,y);
        for(reg j=19;j>=0;--j){
            if(dep[fa[x][j]]>=dep[y]) x=fa[x][j];
        }
        if(x==y) return x;
        for(reg j=19;j>=0;--j){
            if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
        }
        return fa[x][0];
    }
    int main(){
        rd(n);rd(m);
        int tot=0;
        for(reg i=1;i<=n;++i) rd(co[i]),b[++tot]=co[i];
        sort(b+1,b+tot+1);
        tot=unique(b+1,b+tot+1)-b-1;
        kind=tot;
        for(reg i=1;i<=n;++i){
            typ[i]=1;
            
            co[i]=lower_bound(b+1,b+tot+1,co[i])-b;
            //cout<<co[i]<<" ";
            be[co[i]].push_back(i);
        }
       // cout<<endl;
        
        int x,y;
        for(reg i=1;i<=m;++i){
            rd(x);rd(y);add(x,y);add(y,x);
        }
        
        for(reg i=1;i<=n;++i){
            if(!dfn[i]) tarjan(i);
        }
        memset(hd,0,sizeof hd);
        memset(dfn,0,sizeof dfn);
        df=0;cnt=0;
        tot=n;
        int edge=0;
        //cout<<" dcc "<<dcc<<endl;
        for(reg i=1;i<=dcc;++i){
            ++tot;
            typ[tot]=0;
            //cout<<"num ******************"<<tot<<endl;
            for(reg j=0;j<(int)mem[i].size();++j){
            //    cout<<mem[i][j]<<" ";
                typ[mem[i][j]]=1;
                a[++edge][0]=tot;
                a[edge][1]=mem[i][j];
                add(tot,mem[i][j]);
                add(mem[i][j],tot);
            }
            //cout<<endl;
        }
       // cout<<" tot "<<tot<<endl;
        int kuai=0;
        for(reg i=1;i<=tot;++i){
            if(!dfn[i]){
                dfs1(i,++kuai,1);
            }
        }
       // cout<<" kuai "<<kuai<<endl;
        memset(hd,0,sizeof hd);
        cnt=0;
        
        for(reg j=1;j<=19;++j){
            for(reg i=1;i<=n;++i){
                fa[i][j]=fa[fa[i][j-1]][j-1];
            }
        }
        for(reg i=1;i<=kind;++i){
            //cout<<" kind i "<<i<<" ------------------------------- "<<endl;
            int num=be[i].size();
            sort(be[i].begin(),be[i].end(),cmp);
            for(reg j=1;j<num;++j){
                vis[be[i][j]]=vis[be[i][j-1]]=i;
                if(belong[be[i][j]]==belong[be[i][j-1]]){
                    int anc=lca(be[i][j],be[i][j-1]);
                    if(vis[anc]!=i){
                            vis[anc]=i;
                        be[i].push_back(anc);
                    }
                }
            }
            sort(be[i].begin(),be[i].end(),cmp);
            top=0;
            
            for(reg j=0;j<(int)be[i].size();++j){
            //    cout<<" j "<<be[i][j]<<endl;
                while(top&&(!(dfn[sta[top]]<=dfn[be[i][j]]&&dfn[be[i][j]]<=dfn2[sta[top]])))--top;
                if(top) add(sta[top],be[i][j]);
                sta[++top]=be[i][j];
            }
            
            ll has=0;
            for(reg j=0;j<(int)be[i].size();++j){
                if(vis[be[i][j]]!=i+kind){
                    finsz(be[i][j],i);
                //    cout<<" totsz "<<be[i][j]<<" "<<typ[be[i][j]]<<" "<<sz[be[i][j]]<<endl;
                    dfs2(be[i][j],sz[be[i][j]],i);
                    preno+=has*sz[be[i][j]];
                    has+=sz[be[i][j]];
                }
            }
            
            for(reg j=0;j<(int)be[i].size();++j){
                hd[be[i][j]]=0;
                sz[be[i][j]]=0;
            }
            cnt=0;
        }
    //    cout<<" preno "<<preno<<endl;
    //    for(reg i=1;i<=tot;++i){
    //        printf("%d dp %lld %lld
    ",i,dp[i],tag[i]);
    //    }
        memset(vis,0,sizeof vis);
        for(reg i=1;i<=edge;++i){
            add(a[i][0],a[i][1]);
            add(a[i][1],a[i][0]);
        }
        for(reg i=1;i<=tot;++i){
            if(!vis[i]){
                sol(i,0);
            }
        }
        for(reg i=1;i<=n;++i){
            printf("%lld
    ",ans[i]);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/2/19 17:48:21
    */
  • 相关阅读:
    自我介绍
    constructor
    arrow function、function.apply
    for each...in
    类与对象与结构体的区别
    编程语言的发展史
    正则表达式中pw、IDCard和EM匹配
    正则表达式速记
    js中用户名的正则(字符,数字,下划线,减号)
    DOM与document的区别
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10405198.html
Copyright © 2020-2023  润新知