BZOJ5329 [Sdoi2018]战略游戏 圆方树+虚树

https://www.lydsy.com/JudgeOnline/problem.php?id=5329

把仙人掌建成圆方树

对于每次询问建出一棵虚树

然后统计两两点对之间的不同圆点个数和

即为答案

#include<cstdio>
#include<algorithm>
#include<cstring>
#define re register
#define rep(i,s,t) for(re int i=s;i<=t;++i)
using namespace std;
#define ms(a,x) memset(a,x,sizeof a)
#define gi(x) read(x)
#define gii(x,y) read(x),read(y)
#define giii(x,y,z) read(x),read(y),read(z)
#define go1(x) for(re int e=G1.las[x];e;e=G1.nxt[e])
#define go2(x) for(re int e=G2.las[x];e;e=G2.nxt[e])
namespace IO{
    #define gc getchar()
    #define pc(x) putchar(x)
    template<typename T>inline void read(T &x){
        x=0;int f=1;char ch=gc;while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=gc;}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=gc;x*=f;return;
    }
    template<typename T>inline void write(T x=0){
        T wr[51];wr[0]=0;if(x<0)pc('-'),x=-x;if(!x)pc(48);
        while(x)wr[++wr[0]]=x%10,x/=10;while(wr[0])pc(48+wr[wr[0]--]);return;
    }
}
using IO::read;
using IO::write;
const int N=4e5+11;
struct graph{
    int tot;
    int nxt[N],las[N],to[N];
    graph(){
        tot=0,ms(nxt,0),ms(las,0),ms(to,0);
    }
    inline void clear(){
        tot=0,ms(nxt,0),ms(las,0),ms(to,0);
    }
    inline void add(int x,int y){
        nxt[++tot]=las[x];
        las[x]=tot;
        to[tot]=y;
    }
    inline void adde(int x,int y){
        add(x,y),add(y,x);
    }
}G1,G2;
int T,n,m,x,y,dfc,tot;
int low[N],dfn[N],st[N],dis[N],fa[N],
    sz[N],son[N],dep[N],top[N],a[N];
inline void tarjan(int x,int anc){
    re int v;
    low[x]=dfn[x]=++dfc;
    st[++st[0]]=x;
    go1(x){
        v=G1.to[e];
        if(v==anc)continue;
        if(!dfn[v]){
            tarjan(v,x);
            low[x]=min(low[x],low[v]);
            if(low[v]>=dfn[x]){
                int w;
                G2.adde(++tot,x);
                do{
                    w=st[st[0]--];
                    G2.adde(tot,w);
                }while(w!=v);
            }
        }
        else
            low[x]=min(low[x],dfn[v]);
    }
}
inline void dfs1(int x,int anc){
    re int v;
    sz[x]=1,son[x]=0,fa[x]=anc,
    dep[x]=dep[anc]+1,dis[x]=dis[anc]+(x<=n);
    go2(x){
        v=G2.to[e];
        if(v==anc)continue;
        dfs1(v,x);
        sz[x]+=sz[v];
        if(sz[v]>sz[son[x]])
            son[x]=v;
    }
}
inline void dfs2(int x,int up){
    top[x]=up,dfn[x]=++dfc;
    if(son[x])dfs2(son[x],up);
    go2(x){
        int v=G2.to[e];
        if(v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
    low[x]=dfc;
}
inline bool cmp(int a,int b){
    return dfn[a]<dfn[b];
}
inline int lca(int u,int v){
    for(;top[u]^top[v];dep[top[u]]>dep[top[v]]?u=fa[top[u]]:v=fa[top[v]]);
    return dep[u]<dep[v]?u:v;
}
inline void solve(){
    G1.clear(),G2.clear(),dfc=0,st[0]=0;
    ms(dfn,0);
    gii(n,m),tot=n;
    rep(i,1,m)gii(x,y),G1.adde(x,y);
    rep(i,1,tot)
        if(!dfn[i])
            tarjan(i,0);
    dfc=0,dfs1(1,0),dfs2(1,1);
    int q,k,l,ans;
    //rep(i,1,tot)printf("At:%d %d %d\n",dfn[i],low[i],top[i]);
    gi(q);
    for(;q--;){
        gi(k);
        rep(i,1,k)gi(a[i]);
        sort(a+1,a+k+1,cmp);l=k;
        rep(i,1,k-1)a[++l]=lca(a[i],a[i+1]);
        sort(a+1,a+l+1,cmp);
        l=unique(a+1,a+l+1)-a-1;
        ans=a[1]<=n,st[0]=0;
        rep(i,1,l){
            for(;st[0]&&low[st[st[0]]]<dfn[a[i]];)--st[0];
            if(st[0])ans+=dis[a[i]]-dis[st[st[0]]];
            st[++st[0]]=a[i];
        }
        write(ans-k),putchar('\n');
    }
}
int main(){
    gi(T);
    for(;T--;solve());
    return 0;
}
code

猜你喜欢

转载自www.cnblogs.com/Stump/p/9281524.html