[SDOI2018] 战略游戏 点双联通分量 虚树

xiaoxiao2021-02-28  49

这是一道只要前置技能解锁足够即可AC的题 可以BJ不够 泪 我怎么可以不会点双呢。。。

点双缩点 每次建虚树 做完了

#include<cmath> #include<ctime> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<iomanip> #include<vector> #include<string> #include<bitset> #include<queue> #include<set> #include<map> using namespace std; typedef long long ll; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*f; } void print(int x) {if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');} const int N=200100; int n,m,tot; namespace graph { int last[N<<1],ecnt; struct EDGE{int to,nt;}e[N<<3]; inline void add(int u,int v) {e[++ecnt]=(EDGE){v,last[u]};last[u]=ecnt;} int dfn[N<<1],val[N<<1],dep[N<<1],tim; int anc[N<<1][20]; void dfs(int u) { dfn[u]=++tim; for(int i=1;(1<<i)<=dep[u];++i) anc[u][i]=anc[anc[u][i-1]][i-1]; for(int i=last[u],v;i;i=e[i].nt) if((v=e[i].to)!=anc[u][0]) dep[v]=dep[u]+1, val[v]+=val[u], anc[v][0]=u, dfs(v); } inline int getlca(int u,int v) { if(dep[u]<dep[v]) swap(u,v); int len(dep[u]-dep[v]); for(int i=0;(1<<i)<=len;++i) if((1<<i)&len) u=anc[u][i]; if(u==v) return u; for(int i=19;~i;--i) if(anc[u][i]!=anc[v][i]) u=anc[u][i],v=anc[v][i]; return anc[u][0]; } void init() { ecnt=tim=0; memset(val,0,sizeof(val)); memset(dep,0,sizeof(dep)); memset(anc,0,sizeof(anc)); memset(last,0,sizeof(last)); } } int last[N],ecnt; struct EDGE{int to,nt;}e[N<<2]; inline void add(int u,int v) {e[++ecnt]=(EDGE){v,last[u]};last[u]=ecnt;} int dfn[N],low[N],tim; int st[N],top; void tarjan(int u) { dfn[u]=low[u]=++tim, graph::val[u]=1, st[++top]=u; for(int i=last[u],v;i;i=e[i].nt) if(!dfn[v=e[i].to]) { tarjan(v),low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]) { tot++; int tmp(0); do { tmp=st[top--]; graph::add(tmp,tot), graph::add(tot,tmp); }while(tmp!=v); graph::add(u,tot),graph::add(tot,u); } } else low[u]=min(low[u],dfn[v]); } inline bool cmp(int x,int y) {return graph::dfn[x]<graph::dfn[y];} inline void insert(int &res,int x,int y) {res+=graph::val[x]-graph::val[y];} int get_ans(int *s) { register int i,grd,res(0); sort(s+1,s+1+s[0],cmp); int root=graph::getlca(s[1],s[s[0]]); st[1]=root,top=1; for(i=1;i<=s[0];++i) { grd=graph::getlca(s[i],st[top]); while(1) { if(graph::dep[st[top-1]]<=graph::dep[grd]) { insert(res,st[top],grd);top--; if(st[top]!=grd) st[++top]=grd; break; } insert(res,st[top],st[top-1]),top--; } if(s[i]!=st[top]) st[++top]=s[i]; } while(top>1) insert(res,st[top],st[top-1]),top--; return res+(root<=n)-s[0]; } int s[N]; void solve() { register int i,u,v; tot=n=read(),m=read(); for(i=1;i<=m;++i) u=read(),v=read(), add(u,v),add(v,u); tarjan(1); graph::dfs(1); int Q=read(); while(Q--) { s[0]=read(); for(i=1;i<=s[0];++i) s[i]=read(); print(get_ans(s)),puts(""); } } void initial() { graph::init(); tim=top=ecnt=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(last,0,sizeof(last)); } int main() { int T=read(); while(T--) initial(),solve(); return 0; }
转载请注明原文地址: https://www.6miu.com/read-2630954.html

最新回复(0)