uva 1455 王国

题目见刘汝佳白皮书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;
}




                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值