题目的链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3563
首先学了怎么debug:
设置断点,按debug中的go,执行到断点以后不断按step into 如果发现按钮变灰色说明要输入数据了(发现两个坑爹的地方:1.next line不要用(不知道为什么)2.循环读取数据不要把断点设置在scanf附近,也不要用while(1)直接while(scanf()==)
然后是并查集的内容:
首先我写的超时代码:
#include<stdio.h> #include<stdlib.h> #include<string.h> int N,M,Q; int p[10020]; typedef struct edge{ int u; int v; int w; }Edge ; Edge edge[20020]; int pre[10000]; int searchEdge(int u,int v) { int i; for(i=0;i<M;i++) { if(((edge[i].u==u&&edge[i].v==v)||(edge[i].u==v&&edge[i].v==u))&&edge[i].w==1) return i; } return -1; }; int find(int x) { int s=x; int ss=pre[s]; if(searchEdge(s,ss)==-1) { return s; } while(ss!=pre[ss]) { int j; if(searchEdge(s,ss)==-1) { break; } else{ j=ss; ss=pre[ss]; s=j; } } return ss; } void makeset(int x,int y) { int fx=find(x); int fy=find(y); if(fx!=fy) { if(p[fx]>p[fy]) { pre[fy]=fx; } else if(p[fy]==p[fx]) { if(fy>fx) pre[fy]=fx; else pre[fx]=fy; } else pre[fx]=fy; } } int main() { while(scanf("%d",&N)) { memset(edge,0,sizeof(edge)); int i; for(i=0;i<N;i++) { scanf("%d",&p[i]); pre[i]=i; } scanf("%d",&M); for(i=0;i<M;i++) { int a,b; scanf("%d %d",&a,&b); edge[i].u=a; edge[i].v=b; edge[i].w=1; makeset(a,b); } scanf("%d",&Q); for(i=0;i<Q;i++) { char tmp1[100]; int tmp2; scanf("%s",tmp1); int ans=0; if(strcmp(tmp1,"query")==0) { scanf("%d",&tmp2); ans=find(tmp2); if(ans==tmp2) { ans=-1; } printf("%d\n",ans); } else { int a,b; scanf("%d %d",&a,&b); int i; i=searchEdge(a,b); edge[i].w=0; } } } return 0; }
正确:
#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;
}
还有今天看到一个神奇的说法,就是说基本所有的并查集都可以转换为食物链问题,可以尝试一下。