XJOI网上同步测试DAY14 T3

 

思路:tarjan把桥找出来,然后缩点,注意这里的缩点是:如果两个点之间的连边不是桥,那么就把他们缩起来,然后用一个lct维护,对于每个询问,如果官道连接的是两个联通块的话,就把他们连起来,否则我们就把u到v的路径全部染色成0

最后只要询问缩点完的S到缩点完的T的路径上有多少是1就是答案了,最后复杂度:O(nlogn)

至于为什么这么做:因为我们要找必经过的边,这不就是桥吗,那我们先预处理出原来图的桥,然后把图转变成树,之后对于官道来说,它只要是连接了两个在同一个联通块里的点,就表明这段路绝对不可能是必经之路,而对于连接两个连通分量的边,那么它就是新的桥啊!因此它要被新建成为lct中的一条边。

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
struct edge{
    int u,v;
}e[600005];
int n,m;
int tot,go[600005],next[600005],first[600005],Id[600005];
int ch[600005][2],sz,num,sum[600005],w[600005],col[600005],tag[600005];
int dfn[600005],low[600005],pd[600005],vis[600005];
int st[600005],c[600005],belong[600005],fa[600005];
int rev[600005],size[600005];
int read(){
    int t=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
    while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
    return t*f;
}
void insert(int x,int y,int id){
    tot++;
    go[tot]=y;
    next[tot]=first[x];
    first[x]=tot;
    Id[tot]=id;
}
void add(int x,int y,int id){
    insert(x,y,id);
    insert(y,x,id);
}
void tarjan(int x,int Fa){
    dfn[x]=low[x]=++sz;
    for (int i=first[x];i;i=next[i])
     if (Id[i]!=Fa){
            int pur=go[i];
            if (!dfn[pur]){
                tarjan(pur,Id[i]);
                low[x]=std::min(low[x],low[pur]);
                if (low[pur]>dfn[x]) pd[Id[i]]=1;
            }else{
                low[x]=std::min(low[x],dfn[pur]);
            }
     }
}
void bfs(int x){
    int h=1,t=1;c[1]=x;vis[x]=1;belong[x]=++num;
    while (h<=t){
        int now=c[h++];
        for (int i=first[now];i;i=next[i]){
            int pur=go[i];
            if (pd[Id[i]]||vis[pur]) continue;
            c[++t]=pur;
            vis[pur]=1;
            belong[pur]=num;
        }
    }
}
bool isroot(int x){
    return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
void pushdown(int x){
    int l=ch[x][0],r=ch[x][1];
    if (tag[x]!=0){
        int id=(tag[x]==1)?0:1;
        if (l)tag[l]=tag[x];
        if (r)tag[r]=tag[x];
        if (l&&w[l]) col[l]=id;
        if (r&&w[r]) col[r]=id;
        if (l) sum[l]=size[l]*id;
        if (r) sum[r]=size[r]*id;
        tag[x]=0;
    }
    if (rev[x]){
        rev[l]^=1;
        rev[r]^=1;
        rev[x]=0;
        std::swap(ch[x][0],ch[x][1]);
    }
}
void updata(int x){
    int l=ch[x][0],r=ch[x][1];
    if (w[x]==0){
        col[x]=0;sum[x]=0;size[x]=0;
        if (l) sum[x]+=sum[l],size[x]+=size[l];
        if (r) sum[x]+=sum[r],size[x]+=size[r];
        return;
    }
    sum[x]=col[x];size[x]=1;
    if (l) sum[x]+=sum[l],size[x]+=size[l];
    if (r) sum[x]+=sum[r],size[x]+=size[r];
}
void rotate(int x){
    int y=fa[x],z=fa[y],l,r;
    if (ch[y][0]==x) l=0;else l=1;r=l^1;
    if (!isroot(y)){
       if (ch[z][0]==y) ch[z][0]=x;else ch[z][1]=x;    
    }
    fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
    ch[y][l]=ch[x][r];ch[x][r]=y;
    updata(y);updata(x);
}
void splay(int x){
    int top=1;st[1]=x;
    for (int i=x;!isroot(i);i=fa[i])
     st[++top]=fa[i];
    for (int i=top;i;i--)
     pushdown(st[i]);
    while (!isroot(x)){
        int y=fa[x],z=fa[y];
        if (!isroot(y)){
            if (ch[y][0]==x^ch[z][0]==y) rotate(x);
            else rotate(y);
        }
        rotate(x);
    } 
    //updata(x); 
}
void access(int x){
    for (int t=0;x;t=x,x=fa[x]){
        splay(x);
        ch[x][1]=t;
        updata(x);
    }
}
void makeroot(int x){
    access(x);splay(x);rev[x]^=1;
}
int find(int x){
    access(x);splay(x);
    while (ch[x][0]) x=ch[x][0];
    return x;
}
void cut(int x,int y){
    makeroot(x);access(y);splay(y);
    ch[y][0]=fa[ch[y][0]]=0;
    updata(y);
}
void link(int x,int y){
    makeroot(x);fa[x]=y;
}
int main(){
    n=read();m=read();
    for (int i=1;i<=m;i++){
        e[i].u=read();e[i].v=read();
        add(e[i].u,e[i].v,i);
    }
    for (int i=1;i<=n;i++)
     if (!dfn[i]) tarjan(i,0);
    sz=0;num=0;
    for (int i=1;i<=n;i++)
     if (!vis[i]) bfs(i); 
    sz=num;
    for (int i=1;i<=m;i++)
     if (belong[e[i].u]!=belong[e[i].v]){
        sz++;col[sz]=1;tag[sz]=0;sum[sz]=1;w[sz]=1;
        size[sz]=1;
        link(sz,belong[e[i].u]);
        link(sz,belong[e[i].v]);
     } 
    int q=read();
    while (q--){
        int S=read(),T=read(),Num=read(),cnt=0;
        S=belong[S],T=belong[T];
        for (int i=1;i<=Num;i++){
            e[i].u=read();e[i].v=read();
            e[i].u=belong[e[i].u];
            e[i].v=belong[e[i].v];
        }
        for (int i=1;i<=Num;i++){
            if (e[i].u==e[i].v) continue;
            if (find(e[i].u)!=find(e[i].v)){
                w[sz+i]=1;sum[sz+i]=1;
                tag[sz+i]=0;col[sz+i]=1;
                size[sz+i]=1;
                link(e[i].u,sz+i);
                link(e[i].v,sz+i);
                pd[i]=1;
            }else{
                pd[i]=0;
                makeroot(e[i].u);access(e[i].v);splay(e[i].v);
                tag[e[i].v]=1;
            }
        }
        if (find(S)!=find(T)){
            puts("-1");
        }else{
        makeroot(S);access(T);splay(T);
        printf("%d\n",sum[T]);
        }
        for (int i=Num;i>=1;i--){
            if (e[i].u==e[i].v) continue;
            if (pd[i]==1){
                cut(e[i].u,sz+i);
                cut(e[i].v,sz+i);
            }else{
                makeroot(e[i].u);access(e[i].v);splay(e[i].v);
                tag[e[i].v]=-1;
            }
        }
    }
}

 

posted @ 2016-07-15 16:50  GFY  阅读(202)  评论(0编辑  收藏  举报