hdu4674 Trip Advisor,双连通分量,LCA

来源:互联网 发布:数据库的储存过程 编辑:程序博客网 时间:2024/05/16 15:37
这鸟题真是写吐了。

简单来说就是缩圈后成为一个树,然后就变成询问树上某条路径path[a,b]是否包含某点c。
这里我想屎了,用的主席树,空间卡到死各种改,虽然还是给我搞过去了,但是代码量……其实只要用lca搞一下就ok。

但是,没那么简单,不仅要在缩点后的路径上,还得求出路径在a、b、c、lca块的出、入点。

挺复杂的判断才能判断是否能有一个不重复点的路径。详情见代码吧。长度真是不忍直视。

#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;#define NN 100010struct edge{    int v,ne,g;}ed[NN*3];typedef pair<int,int> pii;vector<pii> he;int sta[NN],top;int totb,totdfn,dfn[NN],block[NN],low[NN];int fi[NN];bool vis[NN*3];int te;int link[NN*5][2];struct query{    int a,b,c,lca;}qu[NN];void init_edge(){    te=-1;    memset(fi,-1,sizeof(fi));}void addedge(int fr,int to,int g=0){    ++te;ed[te].ne=fi[fr];fi[fr]=te;    ed[te].v=to;ed[te].g=g;}void tarjan(int u){    int tmp,e,v;    dfn[u]=low[u]=++totdfn;    sta[++top]=u;    for(e=fi[u];e!=-1;e=ed[e].ne)if (!vis[e]){        v=ed[e].v;        vis[e]=vis[e^1]=1;        if (!dfn[v]){            tarjan(v);            if (low[v]<low[u]) low[u]=low[v];            if (low[v]>dfn[u]){                totb++;                do{                    tmp=sta[top--];                    block[tmp]=totb;                }while(tmp!=v);                he.push_back(make_pair(u,v));            }        }        else if (dfn[v]<low[u]) low[u]=dfn[v];    }}int scc(){    int i,u,v;    memset(dfn,0,sizeof(dfn));    totb=top=totdfn=0;    memset(vis,0,sizeof(vis));    he.clear();    tarjan(1);    if (top){        totb++;        do{            i=sta[top--];            block[i]=totb;        }while(i!=1);    }    init_edge();    for(i=0;i<he.size();++i){        u=he[i].first;v=he[i].second;        addedge(block[u],block[v],u);        addedge(block[v],block[u],v);    }    return totb;}vector<pii> vec[NN];int set[NN];int findset(int x){return x==set[x]?x:set[x]=findset(set[x]);}void init_lca(int n){    for(int i=1;i<=n;++i){        vec[i].clear();set[i]=i;vis[i]=0;    }}void tarjan_lca(int u,int fa){    int e;    int v;    for(e=fi[u];e!=-1;e=ed[e].ne){        v=ed[e].v;        if (v==fa) continue;        tarjan_lca(v,u);        set[v]=u;    }    vis[u]=1;    for(e=0;e<vec[u].size();++e){        v=vec[u][e].first;        if (vis[v]) qu[vec[u][e].second].lca=findset(v);    }}struct segtree{    int ls,rs,w;}t[NN*20];int tott;int root[NN];int tn;int build(int l,int r){    int p=++tott;    t[p].w=0;    if (l==r){t[p].ls=t[p].rs=0;return p;}    int m=l+r>>1;    t[p].ls=build(l,m);    t[p].rs=build(m+1,r);    return p;}int insert(int pos,int tl,int tr,int pas){    int p=++tott;    t[p]=t[pas];    t[p].w+=1;    if (t[p].ls==t[p].rs){        return p;    }    int m=tl+tr>>1;    if (pos<=m) t[p].ls=insert(pos,tl,m,t[p].ls);    else t[p].rs=insert(pos,m+1,tr,t[p].rs);    return p;}int query(int pos,int tl,int tr,int a,int b,int lca){    if (tl==tr){        return t[a].w+t[b].w-2*t[lca].w;    }    int m=tl+tr>>1;    if (pos<=m){        return query(pos,tl,m,t[a].ls,t[b].ls,t[lca].ls);    }    else{        return query(pos,m+1,tr,t[a].rs,t[b].rs,t[lca].rs);    }}void dfsbuild(int u,int fa){    root[u]=insert(u,1,tn,root[fa]);    int e,v;    for(e=fi[u];e!=-1;e=ed[e].ne){        v=ed[e].v;        if (v==fa) continue;        dfsbuild(v,u);    }}void dfs(int u,int fa,int bg){    int e,v,lca,tmp;    set[u]=-1;    for(e=0;e<vec[u].size();++e){        lca=vec[u][e].first;        tmp=set[lca];        link[vec[u][e].second][0]=tmp;        link[vec[u][e].second][1]=bg;    }    for(e=fi[u];e!=-1;e=ed[e].ne){        v=ed[e].v;        if (v==fa) continue;        set[u]=ed[e].g;        dfs(v,u,ed[e^1].g);    }    set[u]=-1;}#define py puts("Yes")#define pn puts("No")int main(){    //freopen("4674in.txt","r",stdin);    int n,m,a,b,q,lca,c,i;    int ba,bb,bc;    while(scanf("%d%d",&n,&m)!=EOF){        init_edge();        for(i=1;i<=m;++i){            scanf("%d%d",&a,&b);            addedge(a,b);            addedge(b,a);        }        scanf("%d",&q);        for(i=1;i<=q;++i){            scanf("%d%d%d",&a,&b,&c);            qu[i].a=a;            qu[i].b=b;            qu[i].c=c;        }        tn=scc();      //双连通缩点        init_lca(tn);    //求lca        for(i=1;i<=q;++i){            a=block[qu[i].a];            b=block[qu[i].b];            vec[a].push_back(make_pair(b,i));            vec[b].push_back(make_pair(a,i));        }        tarjan_lca(1,-1);        he.clear();        for(i=1;i<=tn;++i) vec[i].clear();        //求每个问题中a、b、c的出点        for(i=1;i<=q;++i){            vec[block[qu[i].a]].push_back(make_pair(qu[i].lca,i));            vec[block[qu[i].b]].push_back(make_pair(qu[i].lca,i+q));            vec[block[qu[i].c]].push_back(make_pair(qu[i].lca,i+q*2));            vec[block[qu[i].a]].push_back(make_pair(block[qu[i].c],i+q*3));            vec[block[qu[i].b]].push_back(make_pair(block[qu[i].c],i+q*4));        }        memset(set,-1,sizeof(set));        dfs(1,-1,-1);        for(i=1;i<=tn;++i) vec[i].clear();        tott=-1;                 //建立主席树        root[0]=build(1,tn);        dfsbuild(1,0);        for(i=1;i<=q;++i){            a=qu[i].a;b=qu[i].b;c=qu[i].c;lca=qu[i].lca;            if (c==b||c==a){py;continue;}   //排除c==b、c==a            if (a==b) {pn;continue;}        //排除a==b,这样a、b、c肯定不相等了            ba=block[a];bb=block[b];bc=block[c];            if (lca==bc||query(bc,1,tn,root[ba],root[bb],root[lca])) {//首先必须在缩点后的路径上,再判断不合法的                if (lca==ba&&lca==bb){  //a、b、lca同块                    if (bc==lca)  py;                    else pn;                }                else if (lca==ba){      //a与lca同块                    if (bc==lca){           //c与lca同块                        if (link[i+q][0]!=a) py;                        else pn;                    }                    else if (bc==bb){        //c与b同块                        if (link[i+q][1]!=b) py;                        else pn;                    }                    else {                   //都不同块,则在b->lca路径上                        if (link[i+q*2][1]==c) py;                        else if (link[i+q*2][1]!=link[i+q*4][0]) py;                        else pn;                    }                }                else if (lca==bb){        //b与lca同块                    if (bc==lca){                        if (link[i][0]!=b) py;                        else pn;                    }                    else if (bc==ba){                        if (link[i][1]!=a) py;                        else pn;                    }                    else {                        if (link[i+q*2][1]==c) py;                        else if (link[i+q*2][1]!=link[i+q*3][0]) py;                        else pn;                    }                }                else {                  //a、b、lca、都不同块                    if (bc==lca){                        if (link[i][0]!=link[i+q][0]) py;                        else if (link[i][0]==c) py;                        else pn;                    }                    else if (bc==ba){                        if (link[i][1]!=a) py;                        else pn;                    }                    else if (bc==bb){                        if (link[i+q][1]!=b) py;                        else pn;                    }                    else {                        if (link[i+q*2][1]==c) py;                        else if (link[i+q*3][0]==-1){                            if (link[i+q*4][0]!=link[i+q*2][1]) py;                            else pn;                        }                        else {                            if (link[i+q*3][0]!=link[i+q*2][1]) py;                            else pn;                        }                    }                }            }            else pn;        }    }    return 0;}


0 0
原创粉丝点击