您的位置:首页 > 其它

zoj 3261 逆向并查集+离线处理

2015-05-08 15:05 393 查看
题意:给出一些点,每个点有权值,然后有一些边,相连。无向的。然后有一些操作

链接:点我

query a.表示从a出发的能到达的所有点权值最大的点的编号(相同取编号最小,而且权值要比自己大)

destory a,b 表示删除连接a,b的边

逆向并查集。

把没有删除的边先加入并查集,一个集合内表示连通的,根结点为权值最大的点。

然后对于查询离线读入,从最后开始操作,对于删除的点,然后重新加入到并查集中,更新最值。

查询的时候便是查询根结点的值是否大于自身的值

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;

const int MAXN=10010;
int F[MAXN];
int p[MAXN];
int val[MAXN];//最大值的下标
int num[MAXN];//最大值
int find(int x)
{
if(F[x]==-1)return x;
return F[x]=find(F[x]);
}
void bing(int u,int v)
{
int t1=find(u),t2=find(v);
if(t1!=t2)
{
F[t1]=t2;
if(num[t1]>num[t2])
{
num[t2]=num[t1];
val[t2]=val[t1];
}
else if(num[t1]==num[t2] && val[t2]>val[t1])
val[t2]=val[t1];
}
}
map<int,int>mp[MAXN];
struct Edge
{
int u,v;
}edge[20010];
bool used[20010];
struct Node
{
int op;
int u,v;
}node[50010];
int ans[50010];
char str[20];
int main()
{
int n;
int Q;
int m;
int u,v;
bool first=true;
while(scanf("%d",&n)==1)
{
if(first)first=false;
else printf("\n");
memset(F,-1,sizeof(F));
for(int i=0;i<n;i++)
{
scanf("%d",&p[i]);
val[i]=i;
num[i]=p[i];
mp[i].clear();
}

scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
if(u>v)swap(u,v);
mp[u][v]=i;
edge[i].u=u;
edge[i].v=v;
used[i]=false;
}
scanf("%d",&Q);
for(int i=0;i<Q;i++)
{
scanf("%s",&str);
if(str[0]=='q')
{
node[i].op=0;
scanf("%d",&node[i].u);
}
else
{
node[i].op=1;
scanf("%d%d",&u,&v);
if(u>v)swap(u,v);
node[i].u=u;
node[i].v=v;
int tmp=mp[u][v];
used[tmp]=true;
}
}
for(int i=0;i<m;i++)    //没有拆的点连上
if(!used[i])
{
bing(edge[i].u,edge[i].v);
}
int cnt=0;
for(int i=Q-1;i>=0;i--)
{
if(node[i].op==0)
{
u=node[i].u;
int t1=find(u);
if(num[t1]>p[u])ans[cnt++]=val[t1];
else ans[cnt++]=-1;
}
else
{
bing(node[i].u,node[i].v);
}
}
for(int i=cnt-1;i>=0;i--)printf("%d\n",ans[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: