BZOJ 3545: [ONTAK2010]Peaks [Splay启发式合并]

3545: [ONTAK2010]Peaks

题意:带权图,多组询问与一个点通过边权\(\le x\)的边连通的点中点权k大值


又读错题了,输出点一直WA,问的是点权啊

本题加强版强制在线了,那这道题肯定离线啊,边权从小到大加边不就是煞笔提吗

奇怪的是合并的时候先序遍历才行...中序和后序都T了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define lc t[x].ch[0]
#define rc t[x].ch[1]
#define pa t[x].fa
const int N=1e5+5, M=5e5+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

int n, m, Q, val[N], u, v, w, ans[M];
struct meow{
    int u,v,w;
    bool operator <(const meow &r)const{return w<r.w;}
}a[M];
struct qmeow{
    int u,w,k,id;
    bool operator <(const qmeow &r)const{return w<r.w;}
}q[M];
int fa[N];
int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}

struct SplayTree{
    struct meow{int ch[2], fa, v, size, w;}t[N];
    int sz, root;
    inline void ini() {
        for(int i=1; i<=n; i++) t[i].size=t[i].w=1, t[i].v=val[i];
    }
    inline int wh(int x) {return t[pa].ch[1]==x;}
    inline void update(int x) {t[x].size=t[lc].size+t[rc].size+t[x].w;}
    inline void rotate(int x) {
        int f=t[x].fa, g=t[f].fa, c=wh(x);
        if(g) t[g].ch[wh(f)]=x; t[x].fa=g;
        t[f].ch[c]=t[x].ch[c^1]; t[t[f].ch[c]].fa=f;
        t[x].ch[c^1]=f; t[f].fa=x;
        update(f); update(x);
    }
    inline void splay(int x, int tar) {
        for(; pa!=tar; rotate(x))
            if(t[pa].fa != tar) rotate(wh(x)==wh(pa) ? pa : x);
        if(tar==0) root=x;
    }
    void insert(int p) { 
        int x=root, f=0, v=t[p].v; //printf("insert %d  root %d\n",p,x);
        while(x) {
            if(t[x].v == v) {t[x].w++; t[x].size++; splay(x, 0); return;}
            f=x;
            x = v<t[x].v ? lc : rc;
        }
        x=p;
        t[f].ch[ v>t[f].v ]=x; t[x].fa=f; //printf("f %d %d\n",f,x);
        splay(x, 0);  //see(x);
    }
    void order(int x) {
        int l=lc, r=rc; 
        lc=rc=pa=0; t[x].size=t[x].w;
        if(l) order(l);
        if(r) order(r);
        insert(x);
    }
    void Merge(int x, int y) {
        if(x==y) return; //printf("Merge %d %d\n",x,y);
        splay(x, 0); splay(y, 0);
        if(t[x].size > t[y].size) swap(x, y);
        fa[x]=y; root=y;
        order(x);
    }
    int kth(int x, int k) {
        splay(x, 0); int lsize=0;  //printf("kth %d %d  %d\n",x,k,t[x].size);
        if(k>t[x].size) return -1;
        k=t[x].size-k+1; 
        while(x) {
            int _=lsize+t[lc].size;
            if(k<=_) x=lc;
            else if(k<=_+t[x].w) return t[x].v;
            else lsize=_+t[x].w, x=rc;
        }
        return -1;
    }
}S;

int main() {
    freopen("in","r",stdin);
    n=read(); m=read(); Q=read();
    for(int i=1; i<=n; i++) val[i]=read(), fa[i]=i;
    S.ini();
    for(int i=1; i<=m; i++) u=read(),v=read(),w=read(),a[i]=(meow){u,v,w};
    for(int i=1; i<=Q; i++) u=read(),v=read(),w=read(),q[i]=(qmeow){u,v,w,i};

    sort(a+1,a+1+m); sort(q+1, q+1+Q);
    int now=1;
    for(int i=1; i<=Q; i++) {
        int w=q[i].w;
        while(now<=m && a[now].w<=w) S.Merge(find(a[now].u), find(a[now].v)), now++;
        ans[q[i].id] = S.kth(find(q[i].u), q[i].k);
    }
    for(int i=1; i<=Q; i++) printf("%d\n",ans[i]);
}

转载于:https://www.cnblogs.com/candy99/p/6621907.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值