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; }