poj 2985 The k-th Largest Group(线段树+并查集)

来源:互联网 发布:c语言中的运算符 编辑:程序博客网 时间:2024/05/17 06:00

题目链接http://poj.org/problem?id=2985


题意:

有N只猫,刚开始每只猫各自在不同的集合,现在给出M个操作,有两种操作:  

1.把第i只猫和第j只猫所在集合合并。 

 2.查找第i大的集合内有多少只猫。


思路:

操作一,集合合并很容易想到并查集。

操作二,如果每次合并之后进行查找直接遍历一遍,效率O(n^2),很容易超时。所以可以考虑用线段树或者树状数组优化。(毕竟数据结构主要就是查找删除等操作优化)


此题是线段树的单点更新单点查询问题。

sum[i]表示集合内的个数在区间[L,R]的集合的个数;(炒鸡绕口...)

每次更新时,从上而下将集合内的个数在[L,R]的所有区间进行更新(也算是一个小的优化吧)

查询时,只需要判断k<=sum[rt<<1|1],往右;否则往左(找的是第k大,如果是第k小,则比较k和sum[rt<<1])

#include <iostream>#include <cstdio>#include <cmath>using namespace std;#define lson rt<<1,l,mid#define rson rt<<1|1,mid+1,rtypedef long long ll;const int INF=0x3f3f3f3f;const int maxn=2e5+10;int T,n,m;int f[maxn],r[maxn];int sum[maxn<<2];void Make_Set(){for(int i=1;i<=n;i++) f[i]=i,r[i]=1;}int find(int x){return x==f[x]?x:f[x]=find(f[x]);}void build(int rt,int l,int r){sum[rt]=(l==1?n:0);if(l==r) return ;int mid=(l+r)>>1;build(lson);build(rson);}void Update(int rt,int l,int r,int val,bool flag){sum[rt]+=(flag?1:-1);if(l==r) return ;int mid=(l+r)>>1;if(val<=mid) Update(lson,val,flag);else Update(rson,val,flag);}int Query(int rt,int l,int r,int k){if(l==r) return l;int mid=(l+r)>>1;if(k<=sum[rt<<1|1]) return Query(rson,k);else return Query(lson,k-sum[rt<<1|1]);}int main(){#ifndef ONLINE_JUDGEfreopen("test.in","r",stdin);freopen("test.out","w",stdout);#endifwhile(~scanf("%d%d",&n,&m)){Make_Set();build(1,1,n);int op,a,b,k;for(int i=1;i<=m;i++){scanf("%d",&op);if(!op){scanf("%d%d",&a,&b);int ra=find(a);int rb=find(b);if(ra==rb) continue;Update(1,1,n,r[ra],false);Update(1,1,n,r[rb],false);Update(1,1,n,r[ra]+r[rb],true);f[rb]=ra;r[ra]+=r[rb];}else{scanf("%d",&k);printf("%d\n",Query(1,1,n,k));}}}return 0;}


0 0
原创粉丝点击