bzoj 1015 星球大战starwar
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1015
题解:
如果按照题目的意思,每次删点、删边太困难了……于是采用逆向思维,构造出最后的情况,往上加点、加边,用并查集判断连通块即可
[ATTENTION]易犯错误:逆向的最开始连通块个数cnt为n-k个而不是n个,每次加点时cnt++,然后在并集的时候再相应地减
1 #include<cstdio> 2 #define MAXN 400010 3 int n,m,k,head[MAXN],fa[MAXN],cnt,ans1,ans2[MAXN]; 4 bool att[MAXN]; 5 struct edge 6 { 7 int v,next; 8 }e[MAXN]; 9 void add(int i,int x,int y) 10 { 11 e[i]=(edge){y,head[x]}; 12 head[x]=i; 13 } 14 int getfa(int x) 15 { 16 return fa[x]=fa[x]==x?x:getfa(fa[x]); 17 } 18 void work(int dep) 19 { 20 if(dep==k+1) 21 { 22 for(int u=1;u<=n;u++) 23 { 24 if(att[u])continue; 25 for(int i=head[u];i;i=e[i].next) 26 { 27 int v=e[i].v; 28 if(att[v])continue; 29 int p=getfa(u),q=getfa(v); 30 if(p!=q) 31 { 32 fa[q]=p; 33 cnt--; 34 } 35 } 36 } 37 return; 38 } 39 int x; 40 scanf("%d",&x); 41 att[++x]=true; 42 work(dep+1); 43 ans2[++ans1]=cnt; 44 cnt++; 45 att[x]=false; 46 for(int i=head[x];i;i=e[i].next) 47 { 48 int v=e[i].v; 49 if(att[v])continue; 50 int p=getfa(x),q=getfa(v); 51 if(p!=q) 52 { 53 fa[q]=p; 54 cnt--; 55 } 56 } 57 } 58 int main() 59 { 60 scanf("%d%d",&n,&m); 61 int x,y; 62 for(int i=1;i<=m;i++) 63 { 64 scanf("%d%d",&x,&y); 65 add(i<<1,++x,++y); 66 add((i<<1)+1,y,x); 67 } 68 scanf("%d",&k); 69 cnt=n-k; 70 for(int i=1;i<=n;i++)fa[i]=i; 71 work(1); 72 printf("%d\n",cnt); 73 for(int i=ans1;i>=1;i--)printf("%d\n",ans2[i]); 74 return 0; 75 }
PS:感觉自己宛如一个滞胀……竟然在并查集那里卡了好久……