BZOJ 2733 [HNOI2012]永无乡 (权值线段树启发式合并+并查集)
题意:
n<=1e5的图里,在线连边、查询某连通块第k大
思路:
练习线段树合并的好题,因为依然记得上一次启发式合并trie的时候内存爆炸的恐怖,所以这次还是用了动态开点、回收
听说启发式合并splay更快QAQ,学会了试试
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #define fst first #define sc second #define pb push_back #define mp make_pair #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 1e5+100; const int maxm = 6e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); int n,m; int q; int ls[maxn*66],rs[maxn*66],dat[maxn*66]; int root[maxn]; int a[maxn],id[maxn]; int f[maxn]; int find(int x){ return f[x]==x?x:f[x]=find(f[x]); } int tot; queue<int>pool; int New(){ if(!pool.empty()){ int x = pool.front(); pool.pop(); return x; } ++tot; return tot; } void del(int x){ if(!x)return; pool.push(x); return; } int build(int l, int r, int x){ int mid = (l+r)>>1; int p = New(); dat[p]=1; if(l==r)return p; if(x<=mid)ls[p]=build(l,mid,x); else rs[p]=build(mid+1,r,x); return p; } int merge(int p, int q){// leave p if(!p)return q; if(!q)return p; ls[p]=merge(ls[p],ls[q]); rs[p]=merge(rs[p],rs[q]); dat[p]+=dat[q]; ls[q]=rs[q]=dat[q]=0; del(q); return p; } int query(int x, int l, int r, int k){ int mid = (l+r)>>1; if(l==r)return l; if(dat[ls[x]]>=k){ return query(ls[x],l,mid,k); } else{ return query(rs[x],mid+1,r,k-dat[ls[x]]); } } int main() { scanf("%d %d" ,&n, &m); for(int i = 1; i <= n; i++){ f[i]=i; scanf("%d", &a[i]); id[a[i]]=i; root[i]=build(1,n,a[i]); } /*for(int i = 1; i <= n; i++){ printf("-- %d root::%d\n",i,root[i]); } for(int i = 1; i <= tot; i++){ //printf("%d ==== %d %d %d\n",i,ls[i],rs[i],dat[i]); }*/ for(int i = 1; i <= m; i++){ int x,y; scanf("%d %d" ,&x, &y); int t1 = find(x); int t2 = find(y); if(t1!=t2){ root[t1]=merge(root[t1],root[t2]); f[t2]=t1; } } scanf("%d", &q); while(q--){ char op[5]; int x,y; scanf("%s %d %d", op,&x,&y); if(op[0]=='Q'){ int t = find(x); if(dat[root[t]]<y){printf("-1\n");continue;} else printf("%d\n",id[query(root[t],1,n,y)]); } else{ int t1 = find(x); int t2 = find(y); if(t1!=t2){ root[t1]=merge(root[t1],root[t2]); f[t2]=t1; } } } return 0; } /* 5 1 4 3 2 5 1 1 2 7 Q 3 2 Q 2 1 B 2 3 B 1 5 Q 2 1 Q 2 4 Q 2 3 */