la4730(并查集+树状数组)
题意:有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; }
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。