la4730(并查集+树状数组)

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=30&page=show_problem&problem=2731

题意:有t组测试数据,第一个是n,代表有n个城市,标号为0~~n-1,接下来的n行,依次是标号为0~~n-1个城市的坐标,然后有m个操作,road操作代表着将两个点联通,line操作代表询问,直线y=c穿过多少个州,这些州总共有多少个城市。州就是有两个及以上的城市联通所形成的东西........

思路:我的初始思路是用并查集先链接起来,并且设置固定的根节点,并维护它们......想了好久,发现实现起来,非常困难。看《训练指南》上的思路,是用并查集把点连接起来,再把他们按照y坐标来更新.......具体思路是用到了树状数组的成段更新,单点查询......值得注意的地方,就是直线y=c中,c一定是一个带0.5小数的实数。这样的话,我们可以将它的小数部分去掉,但同时,在树状数组更新的时候,最顶端部分,我们要可以不去更新.......其他的看代码吧

 

代码很好看懂,就是用并查集来查询两个城市是否联通,联通的话,不管,否则,就开始更新,把原来所在区域的的州减去,州所附带的城市减去,然后把两个州合并成一个州,再将新形成的州和它所附带的城市加入所在区域。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define min(x,y)  x>y? y:x
#define max(x,y)  x>y? x:y
int c[1000006][2],maxn;
struct node
{
	int zx;
	int zd;
	int ans;
	int father;
}t[100005];
int find(int x)
{
	int root,i=x;
	while(x!=t[x].father)
	x=t[x].father;
	root=x;
	x=i;
	while(x!=t[x].father)
	{
		i=t[x].father;
		t[x].father=root;
		x=i;
	}
	return root;
}
int lowbit(int x)
{
	return x&(-x);
}
void updata(int x,int y,int k)
{
	for(int i=x;i<=maxn;i+=lowbit(i))
	{
		c[i][y]+=k;
	}
}
int getsum(int x,int y)
{
	int sum=0;
	for(int i=x;i>0;i-=lowbit(i))
	{
		sum+=c[i][y];
	}
	return sum;
}
int main()
{
	int text;
	scanf("%d",&text);
	while(text--)
	{
		int n;
		scanf("%d",&n);
		memset(c,0,sizeof(c));
		//for(int i=0;i<100005;i++)
		//t[i].father=i;
		maxn=0;
		for(int i=0;i<n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			y++;
			t[i].father=i;
			t[i].zx=t[i].zd=y;
			t[i].ans=1;
			if(maxn<y)
			maxn=y;
		}
		int m;
		scanf("%d",&m);
		while(m--)
		{
			char ch[10];
			scanf("%s",ch);
			if(ch[0]=='r')
			{
				int tmp,tmp1;
				scanf("%d%d",&tmp,&tmp1);
				int a=find(tmp);
				int b=find(tmp1);
				if(a!=b)
				{
					updata(t[a].zx,0,-1);
					updata(t[a].zd,0,1);
					updata(t[a].zx,1,-t[a].ans);
					updata(t[a].zd,1,t[a].ans);
					updata(t[b].zx,0,-1);
					updata(t[b].zd,0,1);
					updata(t[b].zx,1,-t[b].ans);
					updata(t[b].zd,1,t[b].ans);
					if(a>b)
					swap(a,b);
					t[a].father=b;
					t[b].zx=min(t[a].zx,t[b].zx);
					t[b].zd=max(t[a].zd,t[b].zd);
					t[b].ans+=t[a].ans;
					updata(t[b].zx,0,1);
					updata(t[b].zd,0,-1);
					updata(t[b].zx,1,t[b].ans);
					updata(t[b].zd,1,-t[b].ans);
				}
			}
			else
			{
				double tmp;
				scanf("%lf",&tmp);
				int tmp1=(int)tmp+1;
				printf("%d %d\n",getsum(tmp1,0),getsum(tmp1,1));
			}
		}
	}
	return 0;
}

 

posted @ 2013-07-16 09:26  紫忆  阅读(581)  评论(0编辑  收藏  举报