zoukankan      html  css  js  c++  java
  • [bzoj3331][BeiJing2013]压力(tarjan点双缩点+树上差分)

    题目链接:传送门

    必须经过的点,也就是绕不开的点,就是割点(这就是割点的定义)。那么对于所有询问,非割点的必须经过次数,就是这个点作为询问的开头或者结尾的次数。

    找出所有的点双联通分量,然后缩点(这里注意把割点单独作为一个点),它将是一棵树。然后把询问放到树上,作树上差分。

    要注意的是新图的节点数可能大于旧图,我因为忽略了这个在lca的init函数里没注意上界,wa了很多次。

    代码比较复杂,但都是模块化的,比较好调。

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<stack>
    #include<vector>
    #define maxn 200005
    using namespace std;
    inline void read(int &x){
        x=0;int f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        x*=f;
    }
    int N,M,Q;
    struct node{
        int nex,from,to;
    }edge[maxn<<2][2];
    int head[maxn][2],tot[2];
    inline void insert(int from,int to,int ty){
        edge[++tot[ty]][ty].nex=head[from][ty];
        head[from][ty]=tot[ty];
        edge[tot[ty]][ty].from=from;
        edge[tot[ty]][ty].to=to;
    }
    int dfn[maxn],low[maxn],id,belong[maxn],cnt;
    stack<int>sta;
    bool cut[maxn];
    vector<int> q[maxn];
    void tarjan(int x){
        int flag=0;
        dfn[x]=low[x]=++id;
        sta.push(x);
        for(int i=head[x][0];i;i=edge[i][0].nex){
            int y=edge[i][0].to;
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
                if(dfn[x]<=low[y]){
                    int u;++cnt;++flag;
                    if(flag>1||x!=1)
                        cut[x]=1;
                    do{
                        u=sta.top();//cout<<"out: "<<u<<" "<<x<<endl;
                        sta.pop();
                        q[cnt].push_back(u);
                    }while(u!=y);
                    q[cnt].push_back(x);
                }
            }else
                low[x]=min(low[x],dfn[y]);
        }
    }
    int anc[maxn][20],dept[maxn];
    void dfs1(int x,int u){
        anc[x][0]=u;
        dept[x]=dept[u]+1;
        for(int i=head[x][1];i;i=edge[i][1].nex)
            if(edge[i][1].to^u)
                dfs1(edge[i][1].to,x);
    }
    int num;
    void init(){
        for(int i=1;i<=18;i++)
            for(int a=1;a<=num;a++)
                anc[a][i]=anc[anc[a][i-1]][i-1];
    }
    int lca(int u,int v){
        if(dept[u]<dept[v])
            swap(u,v);
        for(int i=18;i>=0;i--)
            if(dept[anc[u][i]]>=dept[v]){
                //cout<<u<<" "<<i<<" ";
                u=anc[u][i];
            }
                
        //cout<<u<<" "<<v<<endl;
        if(u==v)    
            return u;
        for(int i=18;i>=0;i--)
            if(anc[u][i]!=anc[v][i]){
                u=anc[u][i];
                v=anc[v][i];
            }
        return anc[u][0];
    }
    int sum[maxn];
    void suodian(){
        int u,v;
        num=cnt;
        for(int i=1;i<=N;i++)
            if(cut[i])
                belong[i]=++num;
        for(int x=1;x<=cnt;x++){
            for(int j=0;j<q[x].size();j++){
                int y=q[x][j];
                if(cut[y]){
                    insert(x,belong[y],1);
                    insert(belong[y],x,1);
                }else
                    belong[y]=x;
            }
        }
    }
    int dfs(int x,int u){
        //cout<<x<<" ";
        for(int i=head[x][1];i;i=edge[i][1].nex)
            if(edge[i][1].to^u){
                dfs(edge[i][1].to,x);
                sum[x]+=sum[edge[i][1].to];
            }    
    }
    int final[maxn];
    int main(){
        //freopen("1.in","r",stdin);
        //freopen("1.ans","w",stdout);
        read(N);read(M);read(Q);
        int u,v;
        for(int i=1;i<=M;i++){
            read(u);read(v);
            insert(u,v,0);
            insert(v,u,0);
        }
        tarjan(1);
        suodian();
        dfs1(1,0);
        init();
        //for(int i=1;i<=20;i++)
            //cout<<anc[90623][i]<<" ";
        while(Q--){
            read(u);read(v);
            final[u]++;final[v]++;
            u=belong[u];v=belong[v];
            sum[u]++;sum[v]++;
            int ancs=lca(u,v);
            //cout<<"lca: "<<u<<" "<<v<<" "<<ancs<<endl;
            sum[ancs]--;
            if(ancs!=1)
                sum[anc[ancs][0]]--;
        }
        
        dfs(1,1);
        for(int i=1;i<=N;i++)
            if(!cut[i])
                printf("%d
    ",final[i]);
            else
                printf("%d
    ",sum[belong[i]]);
    }
    View Code
  • 相关阅读:
    bzoj 1030 [JSOI2007]文本生成器
    Swift 学习笔记 (闭包)
    Swift 学习笔记 (函数)
    HTML 学习笔记 JQueryUI(Interactions,Widgets)
    HTML 学习笔记 JQuery(表单,表格 操作)
    HTML 学习笔记 JQuery(animation)
    HTML 学习笔记 JQuery(盒子操作)
    HTML 学习笔记 JQuery(事件)
    HTML 学习笔记 JQuery(DOM 操作3)
    HTML 学习笔记 JQuery(DOM 操作2)
  • 原文地址:https://www.cnblogs.com/sherrlock/p/9919212.html
Copyright © 2011-2022 走看看