输入的第一行是N,表示又N个阵地(0到n-1),下面一行输入每个阵地的武力值,接着输入一个M,下面有M行,表示两点可以想通,接着有Q次查询,query 是查询这个点能不能有帮助他的,destroy表示摧毁两点之间的联系,值得注意的是,他所摧毁的一定是存在的路,而输入的时候也没有重复数据(为了是题目简单一些吧)。
分析:由于是中间有摧毁的步骤,而并查集只能两点链接,不能消除,所以只能倒着处理数据,先把所有能摧毁的全部都不链接,把没有摧毁的链接起来,(可以用扩大第二个数的办法来快速查找路),倒着读的时候遇到摧毁就进行建立,这样可以了,不过还要注意值相等的时候按照下标,就是忘了这点才错了好几次,而且数据之间输出一个空行
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<stack>
using namespace std;
const int maxn = 20005;
const int BigNum = 10000;
struct node
{
int op, u, v;//op等于1代表查询,等于0代表摧毁
}data[maxn*3];//保存查询数据
int f[maxn], val[maxn];
//为了方便查询,把x值扩大10w倍+y值保存下来,use记录这个路是否被摧毁
int h[maxn], use[maxn];
int Find(int x)
{
if(f[x] != x)
f[x] = Find(f[x]);
return f[x];
}
void Union(int u, int v)
{
u = Find(u), v = Find(v);
if(u != v)
{
if(val[u] < val[v])
f[u] = v;
else if(val[u] > val[v])//写成了两个一样的。。。。
f[v] = u;
else if(u < v)
f[v] = u;
else
f[u] = v;
}
}
int main()
{
int N, t=0;
while(scanf("%d", &N) != EOF)
{
int i, M, u, v, Q;
char s[10];
for(i=0; i<N; i++)
{
f[i] = i;
scanf("%d", &val[i]);
}
scanf("%d", &M);
for(i=0; i<M; i++)
{
scanf("%d%d", &u, &v);
if(u > v)swap(u, v);
h[i] = u + v*BigNum;
use[i] = 0;
}
sort(h, h+M);
scanf("%d", &Q);
for(i=0; i<Q; i++)
{
scanf("%s", s);
if(s[0] == ‘d‘)
{
scanf("%d%d", &u, &v);
if(u > v)swap(u, v);
data[i].u = u;data[i].v = v;
data[i].op = 0;
int k = lower_bound(h, h+M, u+v*BigNum) - h;
use[k] = 1;
}
else
{
scanf("%d", &u);
data[i].op = 1, data[i].u = u;
}
}
for(i=0; i<M; i++)
{
u = h[i] % BigNum, v = h[i] / BigNum;
if(use[i] == 0)
Union(u, v);
}
stack<int>sta;
for(i=Q-1; i>=0; i--)
{
if(data[i].op == 0)
Union(data[i].u, data[i].v);
else
{
u = Find(data[i].u);
if(val[u] <= val[data[i].u])
sta.push(-1);
else
sta.push(u);
}
}
if(t++)printf("\n");
while(sta.size())
{
printf("%d\n", sta.top());
sta.pop();
}
}
return 0;
}
/*
5
1 2 3 4 5
4
0 1
1 2
2 3
3 4
5
query 0
query 1
query 2
query 3
query 4
*/