[JSOI2008]星球大战starwar

61.187.179.132:8080/JudgeOnline/showproblem

[JSOI2008]星球大战starwar

Time Limit:3000MS  Memory Limit:165536K
Total Submit:90 Accepted:43
Case Time Limit:1000MS

Description

很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系。某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星 系中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。
但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通 讯通道也开始不可靠起来。现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打 击之后反抗军占据的星球的连通快的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。

Input

输入文件第一行包含两个整数,N (1 <= N <= 2M) 和M (1 <= M <= 200,000),分别表示星球的数目和以太隧道的数目。星球用0~N-1的整数编号。
接下来的M行,每行包括两个整数X, Y,其中(0<=X<>Y

Output

输出文件的第一行是开始时星球的连通块个数。
接下来的N行,每行一个整数,表示经过该次打击后现存星球的连通块个数。

Sample Input

8 13
0 1
1 6
6 5
5 0
0 6
1 2
2 3
3 4
4 5
7 1
7 2
7 6
3 6
5
1
6
3
5
7

Sample Output

1
1
1
2
3
3

Source

额。算法鬼都知道(*^__^*) 就是倒过来然后加点然后用并查集。这没话说。。
关键是如果按我一般的方式用vector表示边的话会TLE囧。。
只好用前向星了。惊讶的发现前向星可以写的怎么短!以后遇到这种情况都用前向星了(*^__^*)
Code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<utility>
#define rep(i,n) for(int i=0;i<n;i++)
#define For(i,a,b) for(int i=a;i<=b;i++)
#define tr(i,x) for(vi::iterator i=x.begin();i!=x.end();i++)
#define all(x) x.begin(),x.end()
#define pb push_back
#define divide cout<<"—————"<<endl;
using namespace std;
const int inf=~0U>>1,maxm=400000,maxn=maxm;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> ii;
ii E[maxm];
int A[maxn],Ans[maxn],S[maxn+1]={0},T[maxm];
bool inSet[maxn]={0},used[maxn]={0};
int F[maxn],n,m,cnt;
void makeset(int x)
{
F[x]=x;cnt++;inSet[x]=true;
}
int find(int x)
{
if(F[x]==x)return x;
return F[x]=find(F[x]);
}
void Union(int i,int j)
{
if(!inSet[i]||!inSet[j])return;
i=find(i);j=find(j);
if(i!=j) F[i]=j,cnt–;
}
int main()
{
//freopen("in","r",stdin);
scanf("%d %d",&n,&m);int s,t;cnt=0;
rep(i,m)
{
scanf("%d %d",&s,&t);
E[i*2]=ii(s,t);
E[i*2+1]=ii(t,s);
S[s]++;S[t]++;
}
for(int i=1;i<=n;i++) S[i]+=S[i-1];
for(int i=2*m-1;i>=0;–i)
T[–S[E[i].first]]=E[i].second;
int k;scanf("%d",&k);
rep(i,k)scanf("%d",A+i),used[A[i]]=true;
rep(i,n)if(!used[i])makeset(i);
rep(i,n)if(!used[i])for(int e=S[i];e<S[i+1];e++)Union(i,T[e]);
Ans[k]=cnt;
for(int i=k-1;i>=0;–i)
{
int t=A[i];makeset(t);
for(int e=S[t];e<S[t+1];e++)Union(t,T[e]);
Ans[i]=cnt;
}
rep(i,k+1)printf("%dn",Ans[i]);
}

7 thoughts on “[JSOI2008]星球大战starwar

  1. …………黑书的并查集一章有讲……只是……为神马我写了125行啊……………………………………………………

Leave a Reply to M四A一 Cancel reply

Your email address will not be published. Required fields are marked *