1. 程式人生 > >bzoj2733: [HNOI2012]永無鄉 線段樹合並

bzoj2733: [HNOI2012]永無鄉 線段樹合並

sss time 以及 編號 mmx oid syn tor eps

永無鄉包含 n 座島,編號從 1 到 n,每座島都有自己的獨一無二的重要度,按照重要度可 以將這 n 座島排名,名次用 1 到 n 來表示。某些島之間由巨大的橋連接,通過橋可以從一個島 到達另一個島。如果從島 a 出發經過若幹座(含 0 座)橋可以到達島 b,則稱島 a 和島 b 是連 通的。現在有兩種操作:B x y 表示在島 x 與島 y 之間修建一座新橋。Q x k 表示詢問當前與島 x連通的所有島中第 k 重要的是哪座島,即所有與島 x 連通的島中重要度排名第 k 小的島是哪 座,請你輸出那個島的編號。
Input
輸入文件第一行是用空格隔開的兩個正整數 n 和 m,分別 表示島的個數以及一開始存在的橋數。接下來的一行是用空格隔開的 n 個數,依次描述從島 1 到島 n 的重要度排名。隨後的 m 行每行是用空格隔開的兩個正整數 ai 和 bi,表示一開始就存 在一座連接島 ai 和島 bi 的橋。後面剩下的部分描述操作,該部分的第一行是一個正整數 q, 表示一共有 q 個操作,接下來的 q 行依次描述每個操作,操作的格式如上所述,以大寫字母 Q 或B 開始,後面跟兩個不超過 n 的正整數,字母與數字以及兩個數字之間用空格隔開。 對於 20%的數據 n≤1000,q≤1000

對於 100%的數據 n≤100000,m≤n,q≤300000

題解:建立權值線段樹,然後線段樹合並即可,復雜度O(nlogn),線段樹合並需要動態開點

/**************************************************************
    Problem: 2733
    User: walfy
    Language: C++
    Result: Accepted
    Time:2552 ms
    Memory:25900 kb
****************************************************************/
 
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define ld long double
#define C 0.5772156649
//#define ls l,m,rt<<1
//#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)
 
using namespace std;
 
const double eps=1e-6;
const int N=100000+10,maxn=2000000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
 
int tot,fa[N],id[N],root[N],ls[maxn],rs[maxn],val[maxn];
inline int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);}
inline void pushup(int rt){val[rt]=val[ls[rt]]+val[rs[rt]];}
void update(int &o,int pos,int l,int r)
{
    o=++tot;
    if(l==r){val[o]=1;return ;}
    int m=(l+r)>>1;
    if(pos<=m)update(ls[o],pos,l,m);
    else update(rs[o],pos,m+1,r);
    pushup(o);
}
int query(int o,int k,int l,int r)
{
    if(l==r)return id[l];
    int m=(l+r)>>1;
    if(k<=val[ls[o]])return query(ls[o],k,l,m);
    else return query(rs[o],k-val[ls[o]],m+1,r);
}
int Merge(int x,int y)
{
    if(!x||!y)return x+y;
    ls[x]=Merge(ls[x],ls[y]);
    rs[x]=Merge(rs[x],rs[y]);
    pushup(x);
    return x;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        int x;scanf("%d",&x);
        update(root[i],x,1,n);
        fa[i]=i;id[x]=i;
    }
    for(int i=1;i<=m;i++)
    {
        int a,b;scanf("%d%d",&a,&b);
        a=Find(a),b=Find(b);fa[b]=a;
        root[a]=Merge(root[a],root[b]);
    }
    int q;scanf("%d",&q);
    while(q--)
    {
        char op[10];int x,y;
        scanf("%s%d%d",op,&x,&y);
        if(op[0]=='B')
        {
            x=Find(x),y=Find(y);
            if(x!=y)
            {
                fa[y]=x;
                root[x]=Merge(root[x],root[y]);
            }
        }
        else
        {
            x=Find(x);
            if(val[root[x]]<y)puts("-1");
            else printf("%d\n",query(root[x],y,1,n));
        }
    }
    return 0;
}
/********************
 
********************/

bzoj2733: [HNOI2012]永無鄉 線段樹合並