[HNOI2012]永無鄉
阿新 • • 發佈:2021-09-06
一石二鳥。
前言
沒啥好說的,練板子水部落格。
題目
講解
聯通性並查集維護,合併兩個區間以及回答詢問有兩個做法。
做法1 平衡樹
直接啟發式暴力單點插入即可。
做法2 線段樹合併
當然是權值線段樹,回答詢問時直接線上段樹上二分就行。
程式碼
C++14 O2
FHQ Treap 649ms 3.16MB
//12252024832524 #include <cstdio> #include <cstring> #include <algorithm> #define TT template<typename T> using namespace std; typedef long long LL; const int MAXN = 100005; const int MOD = 1e9 + 7; int n,m; LL Read() { LL x = 0,f = 1;char c = getchar(); while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();} return x * f; } TT void Put1(T x) { if(x > 9) Put1(x/10); putchar(x%10^48); } TT void Put(T x,char c = -1) { if(x < 0) putchar('-'),x = -x; Put1(x); if(c >= 0) putchar(c); } TT T Max(T x,T y){return x > y ? x : y;} TT T Min(T x,T y){return x < y ? x : y;} TT T Abs(T x){return x < 0 ? -x : x;} struct FHQ_Treap { int l,r,f,siz,val,ID,rd; }t[MAXN]; void up(int x){t[x].siz = t[t[x].l].siz + t[t[x].r].siz + 1;} void split(int now,int val,int &x,int &y) { if(!now) {x = y = 0;return;} else { if(t[now].val <= val) { x = now; split(t[now].r,val,t[now].r,y); t[t[now].r].f = x; } else { y = now; split(t[now].l,val,x,t[now].l); t[t[now].l].f = y; } up(now);//now!!! not x!!! } } int mge(int x,int y) { if(!x || !y) return x|y; if(t[x].rd < t[y].rd) { t[x].r = mge(t[x].r,y); up(x); t[t[x].r].f = x; return x; } else { t[y].l = mge(x,t[y].l); up(y); t[t[y].l].f = y; return y; } } int qval(int now,int rk) { while(t[now].f) now = t[now].f; if(t[now].siz < rk) return -1; while(1) { if(t[t[now].l].siz + 1 == rk) return t[now].ID; if(t[t[now].l].siz >= rk) now = t[now].l; else rk -= t[t[now].l].siz+1,now = t[now].r; } } int Rand(){return (1ll * rand() * rand() * rand() + rand()) % MOD;} void unionSet(int u,int v) { int x,y; while(t[u].f) u = t[u].f; while(t[v].f) v = t[v].f; if(u == v) return; if(t[u].siz < t[v].siz) swap(u,v); int S = t[v].siz; for(int i = 1;i <= S;++ i) { int R = v; v = mge(t[R].l,t[R].r); t[R].l = t[R].r = 0; t[R].siz = 1; split(u,t[R].val-1,x,y); u = mge(mge(x,R),y); } } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); srand(42523); n = Read(); m = Read(); for(int i = 1;i <= n;++ i) t[i] = {0,0,0,1,(int)Read(),i,Rand()};//l,r,f,siz,val,ID,rd for(int i = 1;i <= m;++ i) unionSet(Read(),Read()); for(int T = Read(); T ;-- T) { char c = getchar(); while(c != 'B' && c != 'Q') c = getchar(); if(c == 'B') unionSet(Read(),Read()); else { int ID = Read(); Put(qval(ID,Read()),'\n'); } } return 0; }
線段樹合併 452ms 34.12MB
//12252024832524 #include <cstdio> #include <cstring> #include <algorithm> #define TT template<typename T> using namespace std; typedef long long LL; const int MAXN = 100005; int n,m; LL Read() { LL x = 0,f = 1;char c = getchar(); while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();} return x * f; } TT void Put1(T x) { if(x > 9) Put1(x/10); putchar(x%10^48); } TT void Put(T x,char c = -1) { if(x < 0) putchar('-'),x = -x; Put1(x); if(c >= 0) putchar(c); } TT T Max(T x,T y){return x > y ? x : y;} TT T Min(T x,T y){return x < y ? x : y;} TT T Abs(T x){return x < 0 ? -x : x;} int f[MAXN]; int findSet(int x) { if(x ^ f[x]) f[x] = findSet(f[x]); return f[x]; } int rt[MAXN]; int ch[MAXN<<5][2],tot,siz[MAXN<<5],ans[MAXN<<5]; void up(int x) { if(!x) return; siz[x] = siz[ch[x][0]] + siz[ch[x][1]]; } void Build(int &x,int l,int r,int pos,int val) { if(!x) x = ++tot; if(l == r) {siz[x] = 1;ans[x] = val;return;} int mid = (l+r) >> 1; if(pos <= mid) Build(ch[x][0],l,mid,pos,val); else Build(ch[x][1],mid+1,r,pos,val); up(x); } int mge(int x,int y) { if(!x || !y) return x|y; ch[x][0] = mge(ch[x][0],ch[y][0]); ch[x][1] = mge(ch[x][1],ch[y][1]); siz[x] += siz[y]; ans[x] = Max(ans[x],ans[y]); return x; } void unionSet(int u,int v) { u = findSet(u); v = findSet(v); if(u == v) return; if(u > v) swap(u,v); f[v] = u; rt[u] = mge(rt[u],rt[v]); } void Query(int x,int l,int r,int rk) { if(rk > siz[x]){Put(-1,'\n');return;} if(l == r){Put(ans[x],'\n');return;} int mid = (l+r) >> 1; if(siz[ch[x][0]] >= rk) Query(ch[x][0],l,mid,rk); else Query(ch[x][1],mid+1,r,rk-siz[ch[x][0]]); } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); n = Read(); m = Read(); for(int i = 1;i <= n;++ i) Build(rt[i],1,n,Read(),i),f[i] = i; for(int i = 1;i <= m;++ i) unionSet(Read(),Read()); for(int T = Read(); T ;-- T) { char c = getchar(); while(c != 'B' && c != 'Q') c = getchar(); int x = Read(); if(c == 'Q') Query(rt[findSet(x)],1,n,Read()); else unionSet(x,Read()); } return 0; }