这两道题长得差不多,都有分裂集合的操作,都是先将所有操作离线,然后从最后一步开始倒着模拟,这样一来,分裂就变成合并,也就是从打击以后最终的零散状态,一步步合并,回到最开始所有星球都被连为一个整体的状态,这就能套并查集了。中途的询问结果用栈存下来,输出的时候一个个出栈就好
还有一个共同点,都是科幻风格的,都是星际战争,通信都靠隧道,不知道出题人有没有借鉴的意思
假装这篇博客是我刚写完星球大战这题时写的(其实是一年零两个月二十多天以后,写了zoj那题以后写的 2019年01月25日16:35:27)
[JSOI2008]星球大战
题目描述
很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系。
某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。
但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。
现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打击之后反抗军占据的星球的连通块的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。
输入输出格式
输入格式:
输入文件第一行包含两个整数,$N (1<=N<=2M)$和$M (1<=M<=200,000)$,分别表示星球的数目和以太隧道的数目。星球用$ 0 ~ N−1 $的整数编号。
接下来的 $M$ 行,每行包括两个整数 $X$, $Y$,其中($0<=X<>Y$ 表示星球 $x$ 和星球 $y$ 之间有 “以太” 隧道,可以直接通讯。
接下来的一行为一个整数 $k$ ,表示将遭受攻击的星球的数目。
接下来的 $k$ 行,每行有一个整数,按照顺序列出了帝国军的攻击目标。这 $k$ 个数互不相同,且都在 $0$ 到$n−1$的范围内。
输出格式:
第一行是开始时星球的连通块个数。接下来的 $k$ 行,每行一个整数,表示经过该次打击后现存星球的连通块个数。
输入输出样例
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
1
1
1
2
3
3
说明
[JSOI2008]
源代码
#include<stdio.h>//当年的一些中文注释的编码坏掉了 int n,m,k;//n??μ?mì?±?k???Y?ù???? int ruin[]={};
bool ru[]={};//ê?·?±??Y?ù
int num=;
int ans[]={},top=; struct Edge{
int next,to;
}e[];
int head[]={},cnt=;//40íò??μ?20íòì??T?ò±?
void add(int u,int v)
{
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt++;
} int fa[];//?ó0?e£?2??ó1?e
int find(int x)
{
return fa[x]==x?x:(fa[x]=find(fa[x]));
}
inline bool uni(int x,int y)
{
x=find(x),y=find(y);
if(x==y) return false;
fa[x]=y;
return true;
} int main()
{
//freopen("test.txt","r",stdin);
for(int i=;i<;i++)
fa[i]=i; scanf("%d%d",&n,&m);
for(int i=,u,v;i<m;i++)
{
scanf("%d%d",&u,&v);
//printf("%d %d %d\n",cnt,u,v);
add(u,v);
//printf("%d %d %d\n\n",cnt,v,u);
add(v,u);
}
scanf("%d",&k);
for(int i=;i<k;i++)
scanf("%d",ruin+i),ru[ruin[i]]=true; num=;
for(int i=;i<n;i++)
{
if(!ru[i])
{
for(int j=head[i];j;j=e[j].next)
{
if(!ru[e[j].to])
uni(i,e[j].to);
}
}
}//í3??è?2??Y?ùoóμ?á?í?·?á?num
for(int i=;i<n;i++)
if(find(i)==i&&!ru[i]) num++;
ans[top++]=num;
//printf("^^^^\n");
for(int i=k-;i>=;i--)
{
ru[ruin[i]]=false;
int u=ruin[i];
int m=/*áùê±í3??áaí?·?á??eê§*/;
for(int j=head[u];j;j=e[j].next)
{
if(!ru[e[j].to])
if(uni(u,e[j].to))
{
m++;
//printf("%d %d ",u,e[j].to);
//printf("%d\n",j);
}
}
num-=m-;
ans[top++]=num;
}
top=k;
while(top>=)
{
printf("%d\n",ans[top]);
top--;
} return ;
}
星球大战
Connections in Galaxy War
Connections in Galaxy War
Time Limit: 3 Seconds Memory Limit: 32768 KB
In order to strengthen the defense ability, many stars in galaxy allied together and built many bidirectional tunnels to exchange messages. However, when the Galaxy War began, some tunnels were destroyed by the monsters from another dimension. Then many problems were raised when some of the stars wanted to seek help from the others.
In the galaxy, the stars are numbered from 0 to N-1 and their power was marked by a non-negative integer p. When the star A wanted to seek help, it would send the message to the star with the largest power which was connected with star A directly or indirectly. In addition, this star should be more powerful than the star A. If there were more than one star which had the same largest power, then the one with the smallest serial number was chosen. And therefore, sometimes star A couldn't find such star for help.
Given the information of the war and the queries about some particular stars, for each query, please find out whether this star could seek another star for help and which star should be chosen.
Input
There are no more than 20 cases. Process to the end of file.
For each cases, the first line contains an integer N (1 <= N <= 10000), which is the number of stars. The second line contains N integers p, p, ... , p (0 <= p <= 1000000000), representing the power of the i-th star. Then the third line is a single integer M (0 <= M <= 20000), that is the number of tunnels built before the war. Then M lines follows. Each line has two integers a, b (0 <= a, b <= N - 1, a != b), which means star a and star b has a connection tunnel. It's guaranteed that each connection will only be described once.
In the (M + 2)-th line is an integer Q (0 <= Q <= 50000) which is the number of the information and queries. In the following Q lines, each line will be written in one of next two formats.
"destroy a b" - the connection between star a and star b was destroyed by the monsters. It's guaranteed that the connection between star a and star b was available before the monsters' attack.
"query a" - star a wanted to know which star it should turn to for help
There is a blank line between consecutive cases.
Output
For each query in the input, if there is no star that star a can turn to for help, then output "-1"; otherwise, output the serial number of the chosen star.
Print a blank line between consecutive cases.
Sample Input
2
10 20
1
0 1
5
query 0
query 1
destroy 0 1
query 0
query 1
Sample Output
1
-1
-1
-1
Author: MO, Luyi
Source: ZOJ Monthly, November 2009
源代码
#include<set>
#include<stdio.h>
#include<algorithm> int n,m=-,q; struct Opt{//o==d:a b; o==q: a;
char o;
int a;
int b;
int id;
bool operator < (const Opt & x)const{
return id>x.id;
}
}opt[]; struct Edge{
int s;
int t;
bool operator < (const Edge & x)const{
if(s==x.s) return t<x.t;
return s<x.s;
}
};
std::set<Edge> e;
std::set<Edge>::iterator it;
int ans[]; int p[],mx[],cnt[];
int fa[];
int find(int x)
{
if(fa[x]==x) return x;
fa[x]=find(fa[x]);
cnt[x]=cnt[fa[x]];
mx[x]=mx[fa[x]];
return fa[x];
}
void uni(int x,int y)
{
x=find(x);
y=find(y);
fa[x]=y;
cnt[y]+=cnt[x];
cnt[x]=cnt[y];
if(p[mx[x]]>p[mx[y]])
{
mx[y]=mx[x];
}
else if(p[mx[x]]==p[mx[y]])
{
mx[y]=mx[x]<mx[y]?mx[x]:mx[y];
}
mx[x]=mx[y];
} int main()
{
freopen("test.in","r",stdin);
while(~scanf("%d",&n))
{
if(m>=) printf("\n");
for(int i=;i<n;i++) mx[i]=fa[i]=i,cnt[i]=;
for(int i=;i<n;i++) scanf("%d",p+i);
scanf("%d",&m);
for(int i=,a,b;i<=m;i++)
{
scanf("%d%d",&a,&b);
e.insert({a,b});//查询时e.find({a,b})!=e.end()||e.find({b,a})!=e.end()
}
scanf("%d",&q);
for(int i=;i<=q;i++)
{
int a,b=;
char str[];
scanf("%s%d",str,&a);
if(str[]=='d')
{
scanf("%d",&b);
it=e.find({a,b});
if(it==e.end()) it=e.find({b,a});
e.erase(it);
}
opt[i]={str[],a,b,i};
}
std::sort(opt+,opt++q);
for(it=e.begin();it!=e.end();it++)
uni(it->s,it->t);
int num=;
for(int i=;i<=q;i++)
{
if(opt[i].o=='d')
{
uni(opt[i].a,opt[i].b);
}
else//q
{
find(opt[i].a);
if(p[mx[opt[i].a]]<=p[opt[i].a]) ans[num++]=-;
else ans[num++]=mx[opt[i].a];
}
} while(num>) printf("%d\n",ans[--num]); e.clear();
}
return ;
}
Connections in Galaxy War