刚开始做的时候每一次摧毁都初始化一次 毫无悬念的tle 复杂度O(k*(n+m))
后来瞄了一眼题解 把正向的摧毁改成反向的建立 结果还是tle 复杂度O(k*m)
再仔细看题解才发现不能用
father[i]==i
来判读联通块的数量
应该要用邻接表把所有的边都存起来 然后再建立星球的时候先加答案 然后再扫一遍所有的边 看能不能把两个不同联通块连在一起
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#define test cout<<"*"<<endl;
using namespace std;
const int N=1000000;
vector<int>g[N];
int father[N],dis[N],a[N],n,m;
void init()
{
for(int i=0;i<=n;i++)
{
father[i]=i;
}
}
int Find(int x)
{
if(x==father[x])return x;
father[x]=Find(father[x]);
return father[x];
}
bool unite(int x,int y)
{
int tx=Find(x);
int ty=Find(y);
if(tx==ty)return 0;
father[ty]=tx;
return 1;
}
int b[N],ans[N];
int tj()//联通块的数目
{
int sum=0;
for(int i=0;i<n;i++)
{
if(!b[i]&&father[i]==i)
{
sum++;
}
}
return sum;
}
int main()
{
int k,x,y;
scanf("%d%d",&n,&m);
init();
for(int i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
scanf("%d",&k);
for(int i=0;i<k;i++)
{
scanf("%d",&a[i]);
b[a[i]]=1;
}
for(int i=0;i<n;i++)
if(!b[i])
for(int j=0;j<g[i].size();j++)
if(!b[g[i][j]])
unite(i,g[i][j]);
ans[k]=tj();
for(int i=k-1;i>=0;i--)
{
b[a[i]]=0;
ans[i]=ans[i+1]+1;//多了一个点 先加一
for(int j=0;j<g[a[i]].size();j++)
{
if(b[g[a[i]][j]])continue;
if(unite(g[a[i]][j],a[i]))
ans[i]--;
}
// cout<<"i="<<i<<" ans[i]="<<ans[i]<<endl;
}
for(int i=0;i<=k;i++)
printf("%d\n",ans[i]);
return 0;
}