题目见刘汝佳白皮书p248
sample input
3
10
1 7
5 7
8 6
3 5
5 5
2 3
10 3
7 2
4 1
11 1
11
road 0 1
road 3 5
line 6.5
road 4 2
road 3 8
road 4 7
road 6 9
road 4 1
road 2 7
line 4.5
line 6.5
1
100 100
1
line 100.5
2
10 10
20 20
2
road 0 1
line 15.5
sample output
0 0
2 8
1 5
0 0
1 2
分析:
建立纵坐标的线段树,维护以下几个值:
city:穿过的所有州的城市总数。
state: 穿过的州的总数。
并查集维护以下三个值:
low :这个州的最低点。 up:这个州的最高点
size:这个州包含的城市数。
每加一条边:
如果两个城市在一个州,什么也不用做。
否则先在线段树中删掉两个城市所在的州,再加入两个州合并后的大洲。
注意:只有当它是州(size>1)的时候才能删除。
代码如下:
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<queue> #include<vector> #include<algorithm> #define LL long long #define CLEAR(xxx) memset(xxx,0,sizeof(xxx)) using namespace std; const int maxn=100000+5,maxx=2000000+5; int n,m,x[maxn],y[maxn]; int father[maxn],size[maxn],low[maxn],up[maxn]; int state[maxx*4],city[maxx*4],lazy[maxx*4][2]; int maxsz=0,y1,y2,q; inline void _read(int &x){ char ch=getchar(); bool mark=false; for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true; for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0'; if(mark)x=-x; } int getfa(int x){ return x==father[x]? x: getfa(father[x]); } void pushdown(int o){ int ls=o<<1,rs=ls+1; if(lazy[o][0]){ lazy[ls][0]+=lazy[o][0]; lazy[rs][0]+=lazy[o][0]; state[ls]+=lazy[o][0]; state[rs]+=lazy[o][0]; } if(lazy[o][1]){ lazy[ls][1]+=lazy[o][1]; lazy[rs][1]+=lazy[o][1]; city[ls]+=lazy[o][1]; city[rs]+=lazy[o][1]; } lazy[o][0]=lazy[o][1]=0; } void update(int o,int L,int R,int sz,int v){ if(lazy[o][1]||lazy[o][0]) pushdown(o); if(y1<=L&&y2>=R){ lazy[o][0]+=v; lazy[o][1]+=sz; state[o]+=v; city[o]+=sz; } else if(R>L){ int mid=(L+R)>>1; if(y1<=mid) update(o<<1,L,mid,sz,v); if(y2>mid) update(o*2+1,mid+1,R,sz,v); } } int query(int o,int L,int R){ if(L==R&&L==q) return o; if(lazy[o][1]||lazy[o][0]) pushdown(o); int mid=(L+R)>>1; if(q<=mid) return query(o<<1,L,mid); else return query(o*2+1,mid+1,R); } void Delete(int x){ y1=low[x]; y2=up[x]; update(1,0,maxsz,-size[x],-1); } void merge(int x,int y){ //删除两个小州,建立一个大州 x=getfa(x); y=getfa(y); if(x==y) return ; if(size[x]>1) Delete(x); if(size[y]>1) Delete(y); father[y]=x; size[x]+=size[y]; y1=low[x]=min(low[x],low[y]); y2=up[x]=max(up[x],up[y]); update(1,0,maxsz,size[x],1); } void init(){ int i; _read(n); maxsz=0; for(i=1;i<=n;i++){ _read(x[i]); _read(y[i]); x[i]<<=1; y[i]<<=1; maxsz=max(maxsz,y[i]); } for(i=1;i<=n;i++){ father[i]=i; size[i]=1; low[i]=up[i]=y[i]; } CLEAR(lazy); CLEAR(city); CLEAR(state); } void solve(){ int i,s,t; double temp; string cmd; _read(m); while(m--){ cin>>cmd; if(cmd=="road"){ _read(s); _read(t); s++;t++; //题目中编号是从0~n-1的 merge(s,t); //合并两个州 } else { scanf("%lf",&temp); q=(int)(temp*2+0.5); if(q>maxsz) { puts("0 0"); continue; } int ans=query(1,0,maxsz); printf("%d %d\n",state[ans],city[ans]); } } } int main(){ int T; _read(T); while(T--){ init(); solve(); } return 0; }