洛谷P3224-永无乡题解(权值线段树)
Luogu3224-永无乡
是个正常的线段树合并题,好像还有平衡树的解法(splay/fhqtreap)但我太菜了不会写。。
对重要度建立权值线段树,初始的时候相当于是对每一个节点建立一棵权值线段树,然后处理前m个合并的操作,合并操作可以使用并查集来维护。
注意我们merge的时候要使得并查集fat[a1]=a2的方向跟merge的方向一致,也就是每次我们都merge到并查集的某个集合所有点的父节点上(这里调了一万年)
对于操作二求第k小数,实际上就是权值线段树的基础操作,这棵权值线段树是从小到大排布的,每次我们查询左节点的size是不是大于k,若是则查找右节点第(k-左节点size)小的数;若不是则查找左节点第k小数。注意特判-1的情况(线段树根节点的size小于k)。注意我们返回的是该点的权值(即重要度)而非该点的坐标,需另开数组存储坐标和重要度的对应关系。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsinged long long
#define ld long double
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'
#define debugg(x) cout<<#x<<"="<<x<<endl;
#define debug1(x,y,z) cout<<#x<<' '<<x<<' '<<#y<<' '<<y<<' '<<#z<<' '<<z<<endl;
#define debug cout<<endl<<"*********"<<endl;
#define itn int
#define pii pair<int,int>
//#define mid ((all[now].lo+all[now].ro)/2)
#define mod m1
void fre(){
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
}
void fc(){fclose(stdin);fclose(stdout);}
const int maxn=1e5+10;
const ll inf=0x3f3f3f3f;
int yuan[maxn],rt[maxn];
int dui[maxn];
struct node{
int lo;int ro;int zhi;int pos;
}tree[maxn*20];
int fat[maxn];
int findf(int root){
if(fat[root]==root) return root;
fat[root]=findf(fat[root]);
return fat[root];
}
int n,m,tot;
void pushup(int rnow,int lson,int rson){tree[rnow].zhi=tree[lson].zhi+tree[rson].zhi;}
void add(int lo,int ro,int rnow,int pos){
if(lo==ro){tree[rnow].zhi++;tree[rnow].pos=pos;return;}
int mid=(lo+ro)/2;
if(pos<=mid){
if(tree[rnow].lo==0) tree[rnow].lo=++tot;
add(lo,mid,tree[rnow].lo,pos);
}
else{
if(tree[rnow].ro==0) tree[rnow].ro=++tot;
add(mid+1,ro,tree[rnow].ro,pos);
}
pushup(rnow,tree[rnow].lo,tree[rnow].ro);
}
int req(int lo,int ro,int rnow,int rk){
if(lo==ro) return tree[rnow].pos;
int mid=(lo+ro)/2;
int k1=tree[tree[rnow].lo].zhi;
if(rk>k1) return req(mid+1,ro,tree[rnow].ro,rk-k1);
else return req(lo,mid,tree[rnow].lo,rk);
}
int merge(int rnow1,int rnow2,int lo,int ro){
if(rnow1==0||rnow2==0) return rnow1+rnow2;
if(lo==ro){
tree[rnow1].zhi+=tree[rnow2].zhi;
return rnow1;
}
int mid=(lo+ro)/2;
tree[rnow1].lo=merge(tree[rnow1].lo,tree[rnow2].lo,lo,mid);
tree[rnow1].ro=merge(tree[rnow1].ro,tree[rnow2].ro,mid+1,ro);
pushup(rnow1,tree[rnow1].lo,tree[rnow1].ro);
return rnow1;
}
int main(){
ios;fre();
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>yuan[i];dui[yuan[i]]=i;
if(rt[i]==0) rt[i]=++tot;
fat[i]=i;
add(1,n,rt[i],yuan[i]);
}
for(int i=1;i<=m;i++){
int a1,a2;cin>>a1>>a2;
int fat1=findf(a1);int fat2=findf(a2);
if(fat1!=fat2){
rt[fat2]=merge(rt[fat2],rt[fat1],1,n);
fat[fat1]=fat2;
}
}
cin>>m;
for(int i=1;i<=m;i++){
char a3;int a1,a2;cin>>a3>>a1>>a2;
if(a3=='Q'){
a1=findf(a1);
if(tree[rt[a1]].zhi<a2) cout<<-1<<endl;
else cout<<dui[req(1,n,rt[a1],a2)]<<endl;
}
else{
int fat1=findf(a1);int fat2=findf(a2);
if(fat1!=fat2){
rt[fat2]=merge(rt[fat2],rt[fat1],1,n);
fat[fat1]=fat2;
}
}
}
return 0;
}

浙公网安备 33010602011771号