P1197 [JSOI2008]星球大战

原题链接

考察:并查集+邻接表+逆向思维

kuangbin题单有这道题,但那道题本蒟蒻只看了思路,没有实现,今天做了一下才发现没有那么简单.....

错误思路:

       离线处理,将所有的要连的边先存储,标记要摧毁的点,将还未摧毁的点先连接.再将存储的摧毁的点从尾到头遍历,边涉及本次修复的点的就连接,

结果当然是TLE

正确思路:

       要存储的边用链式前向星存储,每当我们遍历一个被摧毁的点,就通过图的存储遍历到与每个与他相连的点.

关于连通块:

       再摧毁k个星球后,最多剩下n-k个连通块,我们每合并两个点,都会导致连通块减少

这道题和HDU 垃圾邮件那道题不一样的地方在于,那道题删除点后,连接该点的剩余点还在连通块里,这题是否还在与路径有关.主要在于恢复点后,要快速找到与该点连接的点,并查集在这道题是维护是否在一个集合的作用.

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef pair<int,int> pii;
 6 const int N = 4e5+10;
 7 vector<int> v;
 8 int p[N],tot,idx,h[N],ans[N];
 9 bool isknock[N];
10 struct Road{
11     int from,to,next;
12 }road[N];
13 void add(int a,int b)
14 {
15     road[idx].from = a,road[idx].to = b,road[idx].next = h[a],h[a] = idx++;
16 }
17 int findf(int x)
18 {
19     if(p[x]!=x) p[x] = findf(p[x]);
20     return p[x];
21 }
22 int main()
23 {
24 //    freopen("in.txt","r",stdin);
25     int n,m,k;
26     fill(h,h+N,-1);
27     scanf("%d%d",&n,&m);
28     for(int i=1;i<=n;i++) p[i] = i;
29     for(int i=1;i<=m;i++)
30     {
31         int x,y; scanf("%d%d",&x,&y);
32         add(x,y); add(y,x);
33     }
34     scanf("%d",&k);
35     for(int i=1;i<=k;i++){
36         int x; scanf("%d",&x);
37         v.push_back(x);
38         isknock[x]=true;
39     }
40     tot = n-k;//炸掉k个星球,至多有n-k个 连通块 
41     for(int i=1;i<=m*2;i++)
42     {
43         if(!isknock[road[i-1].from]&&!isknock[road[i-1].to])
44         {
45             int x = road[i-1].from,y = road[i-1].to;
46             int px = findf(x),py = findf(y);
47             if(px!=py) p[px] = py,tot--;
48         }
49     }
50     ans[k+1] = tot;
51     for(int j=v.size()-1;j>=0;j--)
52     {
53         tot++;
54         int x = v[j];
55         isknock[x] = 0;
56         for(int i=h[x];i!=-1;i=road[i].next)
57         {
58             int y = road[i].to;
59             int px = findf(x),py = findf(y);
60             if(!isknock[x]&&!isknock[y]&&px!=py)
61             {
62                 p[px] = py; tot --;
63             }
64         }
65         ans[j+1] = tot;
66     }
67     for(int i=1;i<=k+1;i++) printf("%d\n",ans[i]);
68     return 0;
69 } 

 

posted @ 2021-01-21 21:36  acmloser  阅读(71)  评论(0编辑  收藏  举报