bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

  这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并。

  好爽!!!

  写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子。。。),调了好久好久,过了样例,submit,1A!

  哇真的舒服

  调试输出懒得删了QwQ

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#define ll long long
#define which(x) (son[fq[x]][1]==x)
using namespace std;
const int maxn=500010,extar[2]={-2147483647,2147483647};
int n,m,x,y,z,tot,q,cnt;
int fa[maxn],data[maxn],size[maxn],a[maxn],son[maxn][2],fq[maxn],id[maxn],root[maxn];
char ch[maxn];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<‘0‘||c>‘9‘)c==‘-‘&&(f=-1),c=getchar();
    while(c<=‘9‘&&c>=‘0‘)k=k*10+c-‘0‘,c=getchar();
    k*=f;
}
int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}
int search(int x,int k)
{
    //printf("KPM%d %d %d\n",x,k,son[x][1]);
    if(data[x]<k&&son[x][1])return search(son[x][1],k);
    if(data[x]>k&&son[x][0])return search(son[x][0],k);
    return x;
}
void rotate(int x)
{
    int f=fq[x];bool k=which(x);
    son[f][k]=son[x][!k];
    son[x][!k]=f;
    son[fq[f]][which(f)]=x;
    fq[x]=fq[f];
    fq[f]=x;
    if(son[f][k])fq[son[f][k]]=f;
    size[x]=size[f];
    size[f]=size[son[f][0]]+size[son[f][1]]+1;
    //printf("%d %d %d ORZCZL\n",x,f,size[x]);
}
void splay(int x)
{
    while(fq[x])
    {
        int f=fq[x];
        if(!fq[f])
        {
            rotate(x);
            break;
        }
        if(which(x)^which(f))rotate(x);
        else rotate(f);
        rotate(x);
    }
}
void insert(int &x,int w)
{
    //printf("%d %d\n",x,w);
    if(!x){x=++tot;data[tot]=a[w];size[tot]=1;id[x]=w;return;}
    int k=search(x,a[w]);
    //printf("qiguai%d %d %d\n",k,a[w],data[k]);
    //printf("QAQ");
    ++tot;
    data[tot]=a[w];fq[tot]=k;id[tot]=w;
    if(a[w]<data[k])son[k][0]=tot;
    else son[k][1]=tot;
    size[tot]=1;
    while(k)size[k]++,k=fq[k];
    splay(tot);
    x=tot;
}
int rank(int x,int k)
{
    //++cnt;
    //printf("%d %d %d\n",x,k,size[son[x][0]]);
    //if(cnt>10)exit(0);
    if(size[son[x][0]]>=k)return rank(son[x][0],k);
    if((size[son[x][0]]+1)==k)return x;
    return rank(son[x][1],k-size[son[x][0]]-1);
}
void merge(int x,int y)
{
    //printf("WUWUWU%d %d\n",x,y);
    if(son[x][0])merge(son[x][0],root[y]);
    insert(root[y],id[x]);
    if(son[x][1])merge(son[x][1],root[y]);
}
int main()
{
    read(n);read(m);
    for(int i=1;i<=n;i++)
    {
        read(a[i]);
        fa[i]=i;
    }
    //for(int i=1;i<=n;i++)printf("OAO%d\n",gf(i));
    for(int i=1;i<=m;i++)
    {
        read(x);read(y);
        fa[gf(x)]=gf(y);
    }
    //for(int i=1;i<=n;i++)printf("QAQ%d %d\n",gf(i),root[gf(i)]);
    //printf("\n");
    for(int i=1;i<=n;i++)insert(root[gf(i)],i);
    //for(int i=1;i<=n;i++)printf("QAQ%d %d\n",gf(i),root[gf(i)]);
    //printf("%dQQQQQQQQQQQQQQ\n",son[root[gf(1)]][0]);
    read(q);
    for(int i=1;i<=q;i++)
    {
        scanf("%s",ch);read(x);read(y);
        if(ch[0]==‘Q‘)
        {
            x=gf(x);
            //printf("%d %d\n",root[x],size[root[x]]);
            if(size[root[x]]<y)printf("-1\n");
            else
            {
                int pos=rank(root[x],y);
                printf("%d\n",id[pos]),splay(pos),root[x]=pos;
            }
        }
        else
        {
            x=gf(x);y=gf(y);
            if(x!=y)
            {
                //printf("%d %d %d %d\n",root[x],root[y],size[root[x]],size[root[y]]);
                if(size[root[x]]>size[root[y]])swap(x,y);
                fa[x]=y;
                merge(root[x],y);
                root[x]=0;
            }
        }
    }
    return 0;
}

时间: 2024-10-05 05:04:10

bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)的相关文章

[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

B20J_2733_[HNOI2012]永无乡_权值线段树合并

Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛.现在有两种操作:B x y表示在岛 x与岛y之间修建一座新桥.Q x k表示询问当前与岛 x连通的所有岛中第k重要的是哪座岛,即所有与岛 x连通的岛中重要度排名第 k小的岛是哪座,请你输出那个岛的编号. 对于100%的数据n≤100000,m≤n,q≤300000. 分析:读懂题后发现是一道线段树合并的裸题.

【BZOJ2733】永无乡[splay启发式合并or线段树合并]

题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被这坑了. 网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 这道题似乎挺经典的(至少我看许多神犇很早就做了这道题).这道题有两种写法:并查集+(splay启发式合并or线段树合并).我写的是线段树合并,因为--splay不会打+懒得学.

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 是连 通的.现在有两

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

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

[bzoj2733] [HNOI2012]永无乡

写了线段树合并..具体合并姿势和可并堆基本一样.. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=100233,mxnode=maxn*20; 7 int lc[mxnode],rc[mxnode],sz[mxnode],tot; 8 int rt[maxn],f

bzoj 2733 永无乡 - 并查集 - 线段树

永无乡包含 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]永无乡(并查集 + 线段树合并)

传送门 一看到第k大就肯定要想到什么权值线段树,主席树,平衡树之类的 然后就简单了 用并查集判断连通,每个节点建立一颗权值线段树,连通的时候直接合并即可 查询时再二分递归地查找 时间复杂度好像不是很稳定...但hzwer都用这种方法水过.. 正解好像是平衡树+启发式合并,以后学TT #include <cstdio> #include <iostream> #define N 100001 int n, m, q, cnt; int a[N], f[N], sum[N * 20],

【pb_ds】【平衡树启发式合并】【并查集】bzoj2733 [HNOI2012]永无乡

用并查集维护联通性.对每个联通块维护一个平衡树.合并时启发式合并.比较懒,用了pb_ds. 1 #include<cstdio> 2 #include<ext/pb_ds/assoc_container.hpp> 3 #include<ext/pb_ds/tree_policy.hpp> 4 using namespace std; 5 using namespace __gnu_cxx; 6 using namespace __gnu_pbds; 7 tree<