[HNOI2012]永無鄉「線段樹合併」
阿新 • • 發佈:2020-10-22
題目描述
思路分析
- 這題線段樹合併巨好寫啊(
我是不會告訴你其實是因為我不會寫平衡樹的)。然後我也沒怎麼卡常就跑到了洛谷第一頁,平衡樹臉面何在 - 排名的值域很小,所以直接對每個節點開一棵關於排名的權值線段樹,線段數的下標就是排名,往裡面塞個數就行了,這樣查詢 \(k\) 小也很簡單,因為這時候線段樹儲存的是排名位於一段區間內的點的個數,直接找個數為 \(k\) 的那個位置就好了。奧對了,每個葉子節點需要記錄一下塞到這個節點的編號。
- 維護聯通性時用並查集簡單處理就好了,並查集和線段樹同時同向合併,然後好像就沒了,成功變成了線段樹合併裸題
\(Code\)
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define R register #define N 100010 using namespace std; inline int read(){ int x = 0,f = 1; char ch = getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,m,q,fa[N],id[N<<5],tr[N<<5],ls[N<<5],rs[N<<5],root[N<<5],cnt; char op[10]; int find(int x){ return fa[x]==x ? x : (fa[x]=find(fa[x])); } void modify(int &rt,int l,int r,int pos,int idx){//pos將排名轉化為下標 if(!rt)rt = ++cnt; if(l==r){ id[rt] = idx,tr[rt]++;//id記錄編號 return; } int mid = (l+r)>>1; if(pos<=mid)modify(ls[rt],l,mid,pos,idx); else modify(rs[rt],mid+1,r,pos,idx); tr[rt] = tr[ls[rt]] + tr[rs[rt]]; } int merge(int a,int b,int l,int r){//線段樹合併板子 if(!a)return b; if(!b)return a; if(l==r){ tr[a] += tr[b]; return a; } int mid = (l+r)>>1; ls[a] = merge(ls[a],ls[b],l,mid); rs[a] = merge(rs[a],rs[b],mid+1,r); tr[a] = tr[ls[a]] + tr[rs[a]]; return a; } int query(int rt,int l,int r,int k){//查k小相當於查線段樹值剛好等於k的下標(對應的編號) if(tr[rt]<k||!rt)return 0; if(l==r)return id[rt]; int mid = (l+r)>>1; if(k<=tr[ls[rt]])return query(ls[rt],l,mid,k); else return query(rs[rt],mid+1,r,k-tr[ls[rt]]); } int main(){ n = read(),m = read(); for(R int i = 1;i <= n;i++){ fa[i] = i; int x = read(); modify(root[i],1,n,x,i); } for(R int i = 1;i <= m;i++){ int x = read(),y = read(); x = find(x),y = find(y); fa[y] = x; root[x] = merge(root[x],root[y],1,n); } q = read(); for(R int i = 1;i <= q;i++){ scanf("%s",op); if(op[0]=='B'){ int x = read(),y = read(); x = find(x),y = find(y); if(x==y)continue; fa[y] = x; root[x] = merge(root[x],root[y],1,n); }else{ int x = read(),y = read(); x = find(x); int ans = query(root[x],1,n,y); if(!ans){ puts("-1"); continue; } else printf("%d\n",ans); } } return 0; }