peaks

题目描述

给定一个 \(n\) 个节点的无向图,每个点有一个权值 \(h_i\),每条边有一个权值 \(w_i\) 。每次询问一个点,问从此点出发,不经过大于 \(x\) 的边能到达的所有点中,第 \(k\) 大的 \(h\) 是多少。

解法一

每次都是询问小于等于一个值的所有边组成的集合,有单调性。考虑离线询问,将所有边和询问按 \(w_i\)\(x\) 一起从小到大排序排序。需要支持查询第 \(k\) 大,考虑对每个点维护一棵平衡树。加入一条边时,若连接的两个点还没有合并过,就把这两个平衡树合并,并在并查集中维护。

解法二

强制在线做法。

先对原图建立克鲁斯卡尔重构树。对于一个询问操作,先从初始点向上倍增,倍增到可以跳到最大的节点的值且不大于 \(x\) 的那个点,那么由克鲁斯卡尔重构树的性质可得此时这棵子树组成的子图中的所有边的边权都小于等于 \(x\)。问题就转换为在这棵子树的所有叶子节点中查询权值第 \(k\) 大。区间第 \(k\) 大可以用主席树很好地维护。

解法一代码

#include<stdio.h>
#include<algorithm>
#include<stdlib.h>
#include<time.h>
using namespace std;
#define N 100007
#define M 500007
#define lid a[now].ls
#define rid a[now].rs

template<class T>
inline void read(T &x){
    x=0;T flag=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag*=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    x*=flag;
}

struct Node{
    int ls,rs;
    int cnt,val;
}a[M*20];

struct E{
    int u,v,dis;
    int tag;// pos of ans
    //  u,v,dis;
    //  v,k,x;
}t[M<<1];

inline bool Cmp(E x,E y){
    if(x.dis!=y.dis) return x.dis<y.dis;
    return x.tag<y.tag;
}

int ans[M],key[M*20];
int n,m,Q,fa[N],rt[N];

inline int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}

inline void update(int now){
    a[now].cnt=a[lid].cnt+a[rid].cnt+1;
}

int merge(int x,int y){
    if(!x||!y) return x+y;
    if(key[x]<key[y]){
        a[x].rs=merge(a[x].rs,y);
        update(x);
        return x;
    }else{
        a[y].ls=merge(x,a[y].ls);
        update(y);
        return y;
    }
}

void split(int now,int k,int &x,int &y){
    if(!now) x=y=0;
    else{
        if(a[now].val<=k)
            x=now,split(rid,k,rid,y);
        else 
            y=now,split(lid,k,x,lid);
        update(now);
    }
}

inline int kth(int now,int k){
    if(k<=0) return -1;
    while(now){
        if(k<=a[a[now].ls].cnt) now=a[now].ls;
        else if(k==a[a[now].ls].cnt+1) return now;
        else{
            k-=a[a[now].ls].cnt+1;
            now=a[now].rs;
        }
    }
    return -1;
}

int cnt=0;
inline int NewNode(int val){
    a[++cnt]=(Node){0,0,1,val};
    key[cnt]=rand();
    return cnt;
}

inline void insert(int i,int val){
    int x,y;
    split(rt[i],val,x,y);
    rt[i]=merge(merge(x,NewNode(val)),y);
}

void dfs(int now,int i){
    insert(i,a[now].val);
    if(a[now].ls) dfs(a[now].ls,i);
    if(a[now].rs) dfs(a[now].rs,i);
}

inline void swap(int &x,int &y){x^=y,y^=x,x^=y;}
int main(){
    srand(time(NULL));
    read(n),read(m),read(Q);
    int x,y;
    for(int i=1;i<=n;i++) read(x),fa[i]=i,insert(i,x);
    for(int i=1;i<=m;i++)
        read(t[i].u),read(t[i].v),read(t[i].dis);
    for(int i=m+1;i<=m+Q;i++)
        read(t[i].u),read(t[i].dis),read(t[i].v),t[i].tag=i-m;
    sort(t+1,t+1+m+Q,Cmp);
    for(int i=1;i<=m+Q;i++){
        if(t[i].tag){
            x=find(t[i].u);
            int ret=kth(rt[x],a[rt[x]].cnt-t[i].v+1);
            ans[t[i].tag]=(~ret)? a[ret].val:-1;
        }else{
            x=find(t[i].u),y=find(t[i].v);
            if(x==y) continue;
            if(a[rt[x]].cnt>a[rt[y]].cnt) swap(x,y);
            fa[x]=y;
            dfs(rt[x],y);
        }
    }
    for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
}

解法二代码

#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 200007
#define M 500007
#define lid ls[id]
#define rid rs[id]

template<class T>
inline void read(T &x){
    x=0;T flag=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag*=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    x*=flag;
}

struct E_{
    int u,v;
    int dis;
}e_[M];
struct E{
    int next,to;
}e[M];
int n,m,Q,h[N],h_[N],head[N],cnt;
int fa[N],f[N][20],rg[N][2];
int rt[N],ls[N<<4],rs[N<<4],sum[N<<4];

void add(int id,int to){
    e[++cnt]=(E){head[id],to};
    head[id]=cnt;
}

inline bool Cmp1(E_ x,E_ y){return x.dis<y.dis;}

inline int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}

int o=0;
void build(int &id,int lf,int rf){
    id=++o;
    if(lf==rf) return ;
    int mid=(lf+rf)>>1;
    build(lid,lf,mid);
    build(rid,mid+1,rf);
}

int val;
void modify(int pre,int &id,int lf,int rf){
    id=++o;
    sum[id]=sum[pre]+1;
    lid=ls[pre],rid=rs[pre];
    if(lf==rf) return ;
    int mid=(lf+rf)>>1;
    if(val<=mid) modify(ls[pre],lid,lf,mid);
    else modify(rs[pre],rid,mid+1,rf);
}

int query(int pre,int id,int lf,int rf){
    if(lf==rf) return lf;
    int ret=sum[lid]-sum[ls[pre]];
    int mid=(lf+rf)>>1;
    if(val<=ret) return query(ls[pre],lid,lf,mid);
    else{
        val-=ret;
        return query(rs[pre],rid,mid+1,rf);
    }
}

int tot=0,sz;
void dfs(int u){
    rg[u][0]=tot;
    for(int i=1;i<=18;i++)
        f[u][i]=f[f[u][i-1]][i-1];
    if(!head[u]){
        tot++;
        val=lower_bound(h_+1,h_+1+sz,h[u])-h_;
        modify(rt[tot-1],rt[tot],1,sz);
    }
    for(int i=head[u];i;i=e[i].next)
        dfs(e[i].to);
    rg[u][1]=tot;
}

int main(){
    read(n),read(m),read(Q);
    for(int i=1;i<=n;i++) read(h[i]),h_[i]=h[i],fa[i]=i;
    sort(h_+1,h_+1+n);
    sz=unique(h_+1,h_+1+n)-(h_+1);
    for(int i=1;i<=m;i++)
        read(e_[i].u),read(e_[i].v),read(e_[i].dis);
    sort(e_+1,e_+1+m,Cmp1);
    for(int i=1;i<=m;i++){
        int x=find(e_[i].u),
            y=find(e_[i].v);
        if(x==y) continue;
        h[++n]=e_[i].dis;
        fa[n]=fa[x]=fa[y]=n;
        f[x][0]=f[y][0]=n;
        add(n,x),add(n,y);
    }
    build(rt[0],1,sz);
    f[n][0]=n,dfs(n);
    int v,x,k;
    while(Q--){
        read(v),read(x),read(k);
        for(int i=18;~i;i--)
            if(h[f[v][i]]<=x) v=f[v][i];
        val=rg[v][1]-rg[v][0]-k+1;
        if(sum[rt[rg[v][1]]]-sum[rt[rg[v][0]]]<k) printf("-1\n");
        else printf("%d\n",h_[query(rt[rg[v][0]],rt[rg[v][1]],1,sz)]);
    }
}
posted @ 2020-09-10 17:11  Kreap  阅读(402)  评论(0编辑  收藏  举报