bzoj2733: [HNOI2012]永無鄉 線段樹合並
阿新 • • 發佈:2018-06-05
sss time 以及 編號 mmx oid syn tor eps
對於 100%的數據 n≤100000,m≤n,q≤300000
永無鄉包含 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
題解:建立權值線段樹,然後線段樹合並即可,復雜度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]永無鄉 線段樹合並