[bzoj5329][圓方樹][虛樹]戰略遊戲
Description
省選臨近,放飛自我的小Q無心刷題,於是慫恿小C和他一起頹廢,玩起了一款戰略遊戲。 這款戰略遊戲的地圖由n個城市以及m條連線這些城市的雙向道路構成,並且從任意一個城市出發總能沿著道路走到 任意其他城市。現在小C已經佔領了其中至少兩個城市,小Q可以摧毀一個小C沒佔領的城市,同時摧毀所有連線這 個城市的道路。只要在摧毀這個城市之後能夠找到某兩個小C佔領的城市u和v,使得從u出發沿著道路無論如何都不 能走到v,那麼小Q就能贏下這一局遊戲。 小Q和小C一共進行了q局遊戲,每一局遊戲會給出小C佔領的城市集合S 你需要幫小Q數出有多少個城市在他摧毀之後能夠讓他贏下這一局遊戲。
Input
第一行包含一個正整數T,表示測試資料的組數, 對於每組測試資料, 第一行是兩個整數n和m,表示地圖的城市數和道路數, 接下來m行,每行包含兩個整數u和v~(1<=u<v<=n) 表示第u個城市和第v個城市之間有一條道路,同一對城市之間可能有多條道路連線, 第m+1是一個整數q,表示遊戲的局數, 接下來q行,每行先給出一個整數|S|(2<=|S|<=n) 表示小C佔領的城市數量,然後給出|S|個整數s1,s2,…s|S|,(1<=s1<s2<s|S|<=n),表示小C佔領的城市。 1<= T<= 10, 2<= n<= 10^5 且 n-1<= m<= 210^5, 1<= q<= 10^5, 對於每組測試資料,有Sigma|S|<= 2
10^5
Output
對於每一局遊戲,輸出一行,包含一個整數,表示這一局遊戲中有多少個城市在小Q摧毀之後能夠讓他贏下這一局遊戲。
Sample Input
2
7 6
1 2
1 3
2 4
2 5
3 6
3 7
3
2 1 2
3 2 3 4
4 4 5 6 7
6 6
1 2
1 3
2 3
1 4
2 5
3 6
4
3 1 2 3
3 1 2 6
3 1 5 6
3 4 5 6
Sample Output
0
1
3
0
1
2
3
題解
這題嘛… 把圓方樹建出來 答案就是這些點構成的虛樹中的圓點總數 大力排序一下… 如果根也是圓點的話答案要加1
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<vector> #include<ctime> #define LL long long #define mp(x,y) make_pair(x,y) using namespace std; inline int read() { int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void write(int x) { if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); } inline void print(int x){write(x);printf(" ");} struct node{int x,y,next;}a[410000],b[810000];int len1,last1[210000],len2,last2[410000]; void ins_a(int x,int y){len1++;a[len1].x=x;a[len1].y=y;a[len1].next=last1[x];last1[x]=len1;} void ins_b(int x,int y){len2++;b[len2].x=x;b[len2].y=y;b[len2].next=last2[x];last2[x]=len2;} int low[210000],dfn[210000],sta[210000],id,cnt,tp; int r[210000]; void link() { cnt++; for(int i=1;i<=r[0];i++)ins_b(cnt,r[i]),ins_b(r[i],cnt); } void tarjan(int x) { dfn[x]=low[x]=++id;sta[++tp]=x; for(int k=last1[x];k;k=a[k].next) { int y=a[k].y; if(dfn[y]==-1) { tarjan(y);low[x]=min(low[x],low[y]); if(low[y]>dfn[x])ins_b(x,y),ins_b(y,x),tp--; else if(low[y]==dfn[x]) { r[r[0]=1]=x; int i; do { i=sta[tp--]; r[++r[0]]=i; }while(i!=y); link(); } } else low[x]=min(low[x],dfn[y]); } } int in[410000],dpos; int sum[410000],fa[410000][25],dep[410000],bin[25]; int n,m,S,po[210000]; void pre_tree_node(int x) { in[x]=++dpos; for(int i=1;bin[i]<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1]; for(int k=last2[x];k;k=b[k].next) { int y=b[k].y; if(y!=fa[x][0]) { fa[y][0]=x;dep[y]=dep[x]+1;sum[y]=sum[x]+(y<=n); pre_tree_node(y); } } } int lca(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=20;i>=0;i--)if(bin[i]<=dep[x]&&dep[fa[x][i]]>=dep[y])x=fa[x][i]; if(x==y)return x; for(int i=20;i>=0;i--)if(bin[i]<=dep[x]&&fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } bool cmp(int n1,int n2){return in[n1]<in[n2];} int sol() { sort(po+1,po+1+S,cmp); int ret=-2*S; for(int i=2;i<=S;i++) { int LA=lca(po[i-1],po[i]); ret+=sum[po[i-1]]+sum[po[i]]-2*sum[LA]; } int LA=lca(po[S],po[1]); ret+=sum[po[S]]+sum[po[1]]-2*sum[LA]; ret/=2; if(sum[LA]!=sum[fa[LA][0]])ret++; return ret; } int main() { // freopen("01.in","r",stdin); // freopen("a.out","w",stdout); bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1; int T=read(); while(T--) { len1=0;memset(last1,0,sizeof(last1)); len2=0;memset(last2,0,sizeof(last2)); n=read();m=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); ins_a(x,y);ins_a(y,x); } cnt=n;id=tp=0; memset(low,0,sizeof(low)); memset(dfn,-1,sizeof(dfn)); tarjan(1); // for(int i=1;i<=len2;i+=2)printf("%d %d\n",b[i].x,b[i].y); memset(sum,0,sizeof(sum)); dep[1]=0;sum[1]=1;dpos=0; pre_tree_node(1); int Q=read(); while(Q--) { S=read(); for(int i=1;i<=S;i++)po[i]=read(); printf("%d\n",sol()); } } return 0; }