BZOJ 1015 星球大战 并查集+离线

这道题说来真是艰辛,从一开始的RE,到RE,到刚刚的WA,再到AC。 这只能说明我进步的历程,还有我需要不断的加强努力。这道题思路不难,从很久前在黑书中并查集一节就能找到解题的踪影,因为并查集只能并,分不了,所以我们就得离线,倒过来写。只不过这道题真的得审好题目,它问的是剩下的星球中有多少个连通分量,不要搞错了。大概就是这个样子了,加油。

 1 #include<cstdio>
 2 #include<iostream>
 3 #define rep(i,j,k) for(int i= j; i <=k; i++)
 4 #define down(i,j,k) for(int i = j; i >= k; i--)
 5 #define maxn 200005
 6 using namespace std;
 7
 8 int read()
 9 {
10     int s = 0, t = 1; char c = getchar();
11     while( !isdigit(c) ){
12         if( c == ‘-‘ ) t = -1; c = getchar();
13     }
14     while( isdigit(c) ){
15         s = s * 10 + c - ‘0‘; c = getchar();
16     }
17     return s * t;
18 }
19
20 int fa[maxn],rank[maxn];
21 int find(int x)
22 {
23     return x == fa[x] ? x : fa[x] = find(fa[x]);
24 }
25
26 int bing(int x,int y)
27 {
28     if( rank[x] > rank[y] ) fa[y] = x;
29     else fa[x] = y;
30 }
31
32 struct edge{
33 int to; edge* next;
34 };
35 edge *head[maxn*2], *pt, edges[maxn*2];
36
37 void add_edge(int x,int y)
38 {
39     pt->to = x, pt->next = head[y], head[y] = pt++;
40     pt->to = y, pt->next = head[x], head[x] = pt++;
41 }
42
43 int q[maxn*2]; bool used[maxn*2] = {0};
44 int ans[maxn*2];
45
46 int main()
47 {
48     pt = edges; int n = read(), m = read();
49     rep(i,1,n+1) fa[i] = i;
50     rep(i,1,m){
51         int u = read(), v = read();
52         add_edge(u,v);
53     }
54     int k = read();
55     rep(i,1,k){
56         q[i] = read();
57         used[q[i]] = 1;
58     }
59     int tot = 0;
60     rep(i,0,n-1){
61         if( !used[i] ){
62             tot++;
63             for(edge*e = head[i]; e; e=e->next){
64                 int to = e->to;
65                 if( !used[to] ){
66                     int x = find(i), y = find(to);
67                     if( x != y ){
68                         bing(x,y);
69                         tot--;
70                     }
71                 }
72             }
73         }
74     }
75     ans[k+1] = tot;
76     down(i,k,1){
77         int x = q[i];
78         used[x] = 0; tot++;
79         for(edge*e = head[x]; e; e=e->next){
80             int to = e->to;
81             if( !used[to] ){
82                 int xx = find(x), xy = find(to);
83                 if( xx != xy ){
84                     bing(xx,xy); tot--;
85                 }
86             }
87         }
88         ans[i] = tot;
89     }
90     rep(i,1,k+1) printf("%d\n", ans[i]);
91     return 0;
92 }
时间: 2024-10-12 07:17:45

BZOJ 1015 星球大战 并查集+离线的相关文章

BZOJ - 1015【并查集】

1015: [JSOI2008]星球大战starwar Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 5721  Solved: 2639[Submit][Status][Discuss] Description 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的 机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直 接或间接地连接. 但好景不长,很快帝国

ACM学习历程—SNNUOJ 1110 传输网络((并查集 &amp;&amp; 离线) || (线段树 &amp;&amp; 时间戳))(2015陕西省大学生程序设计竞赛D题)

Description Byteland国家的网络单向传输系统可以被看成是以首都 Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的.现在他们开始在其他城市陆 续建立了新的基站,命令“C x“代表在城市x建立了一个新的基站,不会在同一个城市建立多个基站:城市编号为1到n,其中城市1就是首都Bytetown.在建立基站的过程中他们还 会询问某个城市的网络信号是从哪个城市传输过来的,命令”Q x“代表查询城市x的来源城市. Inpu

【bzoj1015】【JSOI2008】【星球大战】【并查集+离线】

Description 非常久曾经.在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器.并攻下了星系中差点儿全部的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,非常快帝国又又一次造出了他的超级武器. 凭借这超级武器的力量.帝国開始有计划地摧毁反抗军占领的星球.因为星球的不断被摧毁,两个星球之间的通讯通道也開始不可靠起来.如今,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的

BZOJ 1015 星球大战

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

zoj 3261 Connections in Galaxy War(并查集+离线逆向操作)

 题目:给出一些点,每个点有权值,然后有一些边,相连.无向的.然后有一些操作 query a.表示从a出发的能到达的所有点权值最大的点的编号(相同取编号最小,而且权值要比自己大) destory a,b 表示删除连接a,b的边 思路并查集,但是要逆向处理,所以先离线读入,从后向前处理,于是对于destroy操作,等价于连接两个点的操作,然后对于每个询问输出即可 #include<cstdio> #include<cstring> #include<cmath> #i

hdu5441(并查集+离线处理)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5441 题意: 根据输入的三个整数n.m.q,表示有n座城市,m条路,q次询问.下面给出m行,每行三个数start.end.w,分别是这条道路的起点城市.终点城市."权值".然后给出q次询问的数值,每次询问的结果是符合条件的路有多少条.条件就是:如果这条路的权值比给的限制值要小,那么这条路就是可行的.注意就是:对于一条路的添加来说,只要a到b之间有路,那么符合条件的路就会有两条,一条是a到b

【JSOI2008】星球大战[并查集]

[JSOI2008]星球大战 决定再做一道并查集水题.... 正难则反 现将要攻击的星球都读入 然后记录已损坏 再将能连的都连上 然后倒着做 就是套路了QAQ 第一次交的代码死于没有认真读题...编号是从0开始的 #include<bits/stdc++.h> using namespace std; const int N=4e5+5,M=2e5+5,inf=0x3f3f3f3f,P=19650827; int n,m,k,cnt=0,ans[N],a[N]; bool broken[N];

hdu 3938 Portal(并查集+离线+kruskal)

搜了题解才把题搞明白.明白之后发现其实题意很清晰,解题思路也很清晰,只是题目表述的很不清晰…… 大意如下—— 给你一个无向图,图中任意两点的距离是两点间所有路径上的某一条边,这条边需要满足两个条件:1. 这条边这两点间某条路径上的最长边:2. 这条边是这两点间所有路径上的最长边中的最短边. 简单来说,假如a到d有两条路径,一条经过b,一条经过d,其中ab = 1, bd = 3, ac = 2, cd = 2,那么abd上的最长边为3,acd上的最长边为2,则ad的距离为2. 如果a, d两点间

BZOJ 1050 旅行(并查集)

很好的一道题. 首先注意,要使的s到t的路径上最大边/最小边的值最小.我们可以尝试一下二分并验证答案. 但是不能二分最大边/最小边. 我们可以二分 最小边的权值.于是算法就出来了. 首先把边权排序.然后枚举最小的边,再依次添加不小于该边的边,直到s和t联通.用并查集维护即可. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include &l