BZOJ 3545 peaks (离线版&&在线版)

离线版

首先将询问和加边一起排个序

对每个节点建一棵主席树,连边时主席树合并即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
typedef long long ll;

const int maxn = 1000010;

int n,m,q;
int a[maxn],b[maxn],fa[maxn],rt[maxn],ans[maxn],p,tot;
struct Node{
    int sz,ls,rs;
}t[maxn<<2];
struct Q{
    int a,b,c,ok,id;
}c[maxn<<2];

int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); }

bool cmp(Q a,Q b){
    if(a.c==b.c) return a.ok<b.ok; // 询问和添加一起排序,并且保证询问前添加已全部完成 
    return a.c<b.c;
}

void modify(int &i,int l,int r,int p){
    if(!i) i=++tot; // 如果原来存在主席树节点就用原来的 
    t[i].sz=1;
    if(l==r) return;
    int mid=(l+r)/2;
    if(p<=mid) modify(t[i].ls,l,mid,p);
    else modify(t[i].rs,mid+1,r,p);
}

int query(int i,int l,int r,int k){
    if(l==r) return l;
    int sum=t[t[i].ls].sz;
    int mid=(l+r)/2;
    if(k<=sum) return query(t[i].ls,l,mid,k);
    else return query(t[i].rs,mid+1,r,k-sum);
}

int merge(int u,int v){ // 线段树合并 
    if(!u||!v) return u|v;
    else if(!t[u].ls&&!t[u].rs){
        t[u].sz+=t[v].sz;
        return u;
    }else{
        t[u].ls=merge(t[u].ls,t[v].ls);
        t[u].rs=merge(t[u].rs,t[v].rs);
        t[u].sz=t[u].sz+t[v].sz;
        return u;
    }
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f;}

int main(){
    n=read(),m=read(),q=read();
    for(int i=1;i<=n;i++) a[i]=read(),b[i]=a[i],fa[i]=i;
    sort(b+1,b+1+n);
    p=unique(b+1,b+1+n)-b-1;
    for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+p,a[i])-b;
    for(int i=1;i<=m;i++) c[i].a=read(),c[i].b=read(),c[i].c=read(),c[i].ok=0;
    for(int i=m+1;i<=m+q;i++) c[i].a=read(),c[i].c=read(),c[i].b=read(),c[i].ok=1,c[i].id=i-m;
    
    sort(c+1,c+1+m+q,cmp);
    
    for(int i=1;i<=n;i++) modify(rt[i],1,p,a[i]);

    for(int i=1;i<=m+q;i++){
        if(c[i].ok==0){
            int u=find(c[i].a),v=find(c[i].b);
            if(u!=v){
                fa[u]=v;
                rt[v]=merge(rt[u],rt[v]);
            }
        }else{
            int u=find(c[i].a);
            if(t[rt[u]].sz<c[i].b) ans[c[i].id]=-1;
            else ans[c[i].id]=b[query(rt[u],1,p,t[rt[u]].sz-c[i].b+1)]; // 第 k 大 
        }
    }
    
    for(int i=1;i<=q;i++){ printf("%d\n",ans[i]); }

    return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/10390309.html