[bzoj2733]永无乡&&[bzoj3545]Peaks

并不敢说完全会了线段树合并,只是至少知道原理写法了。。。还是太菜了,每天被大佬吊锤qwq

我看到的几道线段树合并都是权值线段树的合并。这个算法适用范围应该只是01线段树的。

这两道算入门题了吧。。。

发现粘题面没人看(自己都懒得看),以后粘链接加题意吧。

永无乡

给$n$个没有连边的带权点,动态加边,询问$u$所在连通块权值第$k$大的点是什么。$n \leq 1e5 , q\leq 3e5$

离线永无乡??

给定森林,点有点权有重复!,边有边权。询问$u$所在连通块,只能走边权小于$w$的边,可达的权值第$k$大的点编号!是什么。$n \leq 1e5 , m,q \leq 5e5$ 被坑的巨惨qwq

后面的离线一下,按边权从小到大加进去就和永无乡一样了。

并查集维护连通性,并将两个连通块的权值线段树合并。询问就是在所在连通块线段树二分找。$(O(nlogn))$

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
inline int read(){
    int r=0,c=getchar();
    while(!isdigit(c))c=getchar();
    while(isdigit(c))
    r=r*10+c-‘0‘,c=getchar();
    return r;
}
int fa[N],rt[N],n,m;
int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
struct Node{
    int L,R,sum;
}T[N*20];
int sz;
#define ls T[o].L
#define rs T[o].R
void pullup(int o){
    T[o].sum=T[ls].sum+T[rs].sum;
}
void ins(int &o,int l,int r,int v){
    if(!o)o=++sz;
    if(l==r){
        T[o].sum=1;return;
    }
    int mid=l+r>>1;
    if(v<=mid)ins(ls,l,mid,v);
    else ins(rs,mid+1,r,v);
    pullup(o);
}
int merge(int x,int y){
    if(!x)return y;
    if(!y)return x;
    T[x].L=merge(T[x].L,T[y].L);
    T[x].R=merge(T[x].R,T[y].R);
    pullup(x);
    return x;
}
int query(int o,int l,int r,int rk){
    if(l==r)return l;
    int mid=l+r>>1;
    if(rk<=T[ls].sum)return query(ls,l,mid,rk);
    else return query(rs,mid+1,r,rk-T[ls].sum);
}
void Link(int x,int y){
    int u=find(x),v=find(y);
    fa[u]=v;rt[v]=merge(rt[u],rt[v]);
}
int a[N],id[N];
void init(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    a[i]=read(),id[a[i]]=fa[i]=i;
    while(m--){
        int u=read(),v=read();
        fa[find(u)]=find(v);
    }
    for(int i=1;i<=n;i++)
    ins(rt[find(i)],1,n,a[i]);
}
void solve(){
    m=read();
    char s[10];
    while(m--){
        scanf("%s",s);
        if(s[0]==‘B‘){
            int u=read(),v=read();
            Link(u,v);
        }
        else{
            int u=find(read()),rk=read();
            if(T[rt[u]].sum<rk)puts("-1");
            else printf("%d\n",id[query(rt[u],1,n,rk)]);
        }
    }
}
int main(){
    init();
    solve();
}

2733

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
const int M=500010;
inline int read(){
    int r=0,c=getchar();
    while(!isdigit(c))c=getchar();
    while(isdigit(c))
    r=r*10+c-‘0‘,c=getchar();
    return r;
}
int n,m,q;
struct Edge{
    int u,v,w;
    friend bool operator < (Edge p,Edge q){
        return p.w<q.w;
    }
}e[M];
struct ask{
    int u,w,k,ans,id;
}a[M];
bool cmpw(ask p,ask q){
    return p.w<q.w;
}
bool cmpid(ask p,ask q){
    return p.id<q.id;
}
int fa[N],h[N],t[N],id[N];
inline int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
int rt[N],sz;
struct Node{
    int L,R,sum;
}T[N*40];
#define ls T[o].L
#define rs T[o].R
#define mid (l+r>>1)
inline void pullup(int o){
    T[o].sum=T[ls].sum+T[rs].sum;
}
void ins(int &o,int l,int r,int val){
    if(!o)o=++sz;
    if(l==r){
        T[o].sum=1;return;
    }
    if(val<=mid)ins(ls,l,mid,val);
    else ins(rs,mid+1,r,val);
    pullup(o);
}
int query(int o,int l,int r,int rk){
    if(l==r){
        return t[l];
    }
    if(rk<=T[ls].sum)return query(ls,l,mid,rk);
    else return query(rs,mid+1,r,rk-T[ls].sum);
}
int merge(int x,int y){
    if(!x)return y;
    if(!y)return x;
    if(!T[x].L&&!T[x].R){
        T[x].sum+=T[y].sum;
        return x;
    }
    T[x].L=merge(T[x].L,T[y].L);
    T[x].R=merge(T[x].R,T[y].R);
    pullup(x);return x;
}
inline void Link(int x,int y){
    x=find(x),y=find(y);
    if(x==y)return;
    fa[y]=x;
    rt[x]=merge(rt[x],rt[y]);
}
void init(){
    n=read(),m=read(),q=read();
    for(int i=1;i<=n;i++)
    h[i]=t[i]=read(),fa[i]=i;
    sort(t+1,t+n+1);
    for(int i=1;i<=n;i++){
        h[i]=lower_bound(t+1,t+n+1,h[i])-t;
        ins(rt[i],1,n,h[i]);
    }
    for(int i=1;i<=m;i++)
    e[i].u=read(),e[i].v=read(),e[i].w=read();
    sort(e+1,e+m+1);
    for(int i=1;i<=q;i++)
    a[i].u=read(),a[i].w=read(),a[i].k=read(),a[i].id=i;
    sort(a+1,a+q+1,cmpw);
}
void solve(){
    int now=1;
    for(int i=1;i<=q;i++){
        int lim=a[i].w,rk=a[i].k;
        while(e[now].w<=lim&&now<=m){
            Link(e[now].u,e[now].v);now++;
        }
        int u=find(a[i].u),siz=T[rt[u]].sum;
        if(siz<rk){
            a[i].ans=-1;continue;
        }
        else rk=siz-rk+1;
        a[i].ans=query(rt[u],1,n,rk);
    }
    sort(a+1,a+q+1,cmpid);
    for(int i=1;i<=q;i++)
    printf("%d\n",a[i].ans);
}
int main(){
    init();
    solve();
}

3545

时间: 2024-10-10 07:22:01

[bzoj2733]永无乡&&[bzoj3545]Peaks的相关文章

BZOJ2733 永无乡【splay启发式合并】

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含

bzoj2733 永无乡 平衡树按秩合并

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 题意:动态连边,求出某个联通块中权值第$k$小的点. 首先,看到名次果断想平衡树……查询这个问题很好解决,但是合并……恐怕只能暴力修改了吧…… 这时候我们需要一个武器:启发式合并,通俗的讲就是小的插到大的里面去突然污了起来.我们可以想象一下,如果把大的那棵树合并到小的那棵去,那么每个节点暴力合并……时间代价不堪设想……因此按秩合并可以有效减短合并时间……然后就是暴力插点删点就行了……

bzoj2733 永无乡 splay树的启发式合并

https://vjudge.net/problem/HYSBZ-2733 给一些带权点,有些点是互相连通的, 然后给出2种操作,在两点间加一条边,或者询问一个点所在的连通块内的第k小值的编号 并查集辅助+splay的启发式合并就行 由于结构简单,动态开点线段树合并也可以做 我写的是splay,由于一个奇怪的bug,我一气之下把之前的核心代码里的我自己写的splay和rotate代码全换成板子了 #include <bits/stdc++.h> #define endl '\n' #defin

[BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)

Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k

bzoj2733: [HNOI2012]永无乡(splay)

2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3778  Solved: 2020 Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两

【bzoj2733】[HNOI2012]永无乡 线段树合并

Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k

HNOI2012永无乡

[HNOI2012]永无乡 Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x

HNOI 2012 永无乡

codevs 1477 永无乡 http://codevs.cn/problem/1477/ 2012年湖南湖北省队选拔赛 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连通的.现

BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)

不难...treap + 启发式合并 + 并查集 搞搞就行了 ---------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep(i, n) for(int i = 0; i &l