P3302-[SDOI2013]森林【主席树,LCA,启发式合并】
生活随笔
收集整理的這篇文章主要介紹了
P3302-[SDOI2013]森林【主席树,LCA,启发式合并】
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P3302
題目大意
nnn個(gè)點(diǎn)的一個(gè)森林,要求支持以下操作
解題思路
需要支持查詢第kkk大,是必定使用主席樹的,所以考慮如何合并兩棵樹可以更快。
考慮啟發(fā)式合并,每次將小的點(diǎn)合并到大的點(diǎn)上面,那樣每個(gè)點(diǎn)最多被合并log?n\log nlogn次。也就是每次合并我們就將小的那顆樹完全重構(gòu)
考慮如何查詢,我們可以用主席樹上儲(chǔ)存根節(jié)點(diǎn)到該點(diǎn)的每個(gè)數(shù)的個(gè)數(shù),然后查詢時(shí)我們可以用兩個(gè)點(diǎn)到根節(jié)點(diǎn)的答案減去他們的lcalcalca處和lcalcalca的父節(jié)點(diǎn)處的答案即可。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=8e4+10,M=N*600,K=17; struct node{ll to,next; }a[N*2]; ll n,m,t,cnt,tot; ll w[N],b[N],ls[N],rt[N]; ll root[N],siz[N],dep[N],f[N][K]; struct Seq_Tree{ll ls[M],rs[M],w[M],cnt;void Build(ll &x,ll l,ll r){if(!x)x=++cnt;w[x]=0;if(l==r)return;ll mid=(l+r)>>1;Build(ls[x],l,mid);Build(rs[x],mid+1,r);return;}ll Change(ll y,ll l,ll r,ll pos){ll x=++cnt,mid=(l+r)>>1;w[x]=w[y]+1;ls[x]=ls[y];rs[x]=rs[y];if(l==r)return x;if(pos<=mid)ls[x]=Change(ls[y],l,mid,pos);else rs[x]=Change(rs[y],mid+1,r,pos);return x;}ll Ask(ll x,ll y,ll lca,ll fa,ll l,ll r,ll k){if(l==r)return b[l];ll mid=(l+r)>>1,val=w[ls[x]]+w[ls[y]]-w[ls[lca]]-w[ls[fa]];if(val>=k)return Ask(ls[x],ls[y],ls[lca],ls[fa],l,mid,k);return Ask(rs[x],rs[y],rs[lca],rs[fa],mid+1,r,k-val);} }T; void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;return; } void dfs(ll x,ll fa){siz[root[x]]++;f[x][0]=fa;dep[x]=dep[fa]+1;for(ll i=1;i<K;i++)f[x][i]=f[f[x][i-1]][i-1];rt[x]=T.Change(rt[fa],1,cnt,w[x]);for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;root[y]=root[x];dfs(y,x);}return; } void Connect(ll x,ll y){if(siz[root[x]]<siz[root[y]])swap(x,y);root[y]=root[x];dfs(y,x);addl(x,y);return; } ll LCA(ll x,ll y){if(dep[x]>dep[y])swap(x,y);for(ll i=K-1;i>=0;i--)if(dep[f[y][i]]>=dep[x])y=f[y][i];if(x==y)return x;for(ll i=K-1;i>=0;i--)if(f[y][i]!=f[x][i])x=f[x][i],y=f[y][i];return f[x][0]; } int main() {ll testcase;scanf("%lld",&testcase);scanf("%lld%lld%lld",&n,&m,&t);for(ll i=1;i<=n;i++)scanf("%lld",&w[i]),b[++cnt]=w[i];sort(b+1,b+1+cnt);cnt=unique(b+1,b+1+cnt)-b-1;for(ll i=1;i<=n;i++)w[i]=lower_bound(b+1,b+1+cnt,w[i])-b;for(ll i=1;i<=m;i++){ll x,y;scanf("%lld%lld",&x,&y);addl(x,y);}T.Build(rt[0],1,cnt);for(ll i=1;i<=n;i++)if(!root[i]){root[i]=i;dfs(i,0);}ll last=0;for(ll i=1;i<=t;i++){char op[4];ll x,y,k;scanf("%s",op);if(op[0]=='Q'){scanf("%lld%lld%lld",&x,&y,&k);x^=last;y^=last;k^=last;ll lca=LCA(x,y);last=T.Ask(rt[x],rt[y],rt[lca],rt[f[lca][0]],1,cnt,k);printf("%lld\n",last);}else{scanf("%lld%lld",&x,&y);x^=last;y^=last;Connect(x,y);}}return 0; }總結(jié)
以上是生活随笔為你收集整理的P3302-[SDOI2013]森林【主席树,LCA,启发式合并】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AT4352-[ARC101C] Rib
- 下一篇: nssl1487-图