Loading

洛谷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;
}
posted @ 2021-03-25 17:59  14long  阅读(80)  评论(0)    收藏  举报