BZOJ 3123 SDOI2013 森林
Posted lcf2000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3123 SDOI2013 森林相关的知识,希望对你有一定的参考价值。
题目链接:森林
这道题想法很显然。既然只有加边而没有删边,那么每次启发式合并就可以了。查询路径\(k\)小似乎需要主席树,那么把主席树和倍增表一起暴力重构就好了。
然后发现这样的空间复杂度是\(O(n\log^2n)\)的。感觉非常不靠谱,于是滚去写了个节点回收站……然后发现主席树节点回收的话每个节点会被\(dfs\)到多次,还需要一些特判……
然后就是一直\(RE\)……由于题目是强制在线的那么就应该是\(Wa\)了。但是对拍了\(6W\)组数据没出错我还能说什么呢……
最后突然发现,我的倍增表在合并的时候好像没有清空……本来以为这样不会出问题,但是由于我的倍增的一些写法,就跳到了一些奇怪的节点上去……以后还是不那么写了,老老实实从上界开始\(for\)吧
下面贴代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define maxn 80010 #define MAXN 1500010 using namespace std; typedef long long llg; int n,m,T,d[maxn],ld,rt[maxn],a[maxn],qz,lans; int head[maxn],next[maxn<<1],to[maxn<<1],tt; int sumv[MAXN],le[MAXN],ri[MAXN],q[MAXN],lq,rq,L; int f[maxn][17],dep[maxn],fa[maxn],siz[maxn]; bool isin[MAXN]; int getint(){ int w=0;bool q=0; char c=getchar(); while((c>‘9‘||c<‘0‘)&&c!=‘-‘) c=getchar(); if(c==‘-‘) c=getchar(),q=1; while(c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar(); return q?-w:w; } int find(int x){return fa[fa[x]]==fa[x]?fa[x]:fa[x]=find(fa[x]);} void qpush(int x){if(isin[x]) return; isin[x]=1;q[rq++]=x,rq%=MAXN;} int qtop(){ if(lq==rq) return ++qz; int now=q[lq++]; lq%=MAXN; isin[now]=0; return now; } void link(int x,int y){ to[++tt]=y;next[tt]=head[x];head[x]=tt; to[++tt]=x;next[tt]=head[y];head[y]=tt; } int build(int u,int l,int r){ int now=qtop(),mid=(l+r)>>1; le[now]=le[u]; ri[now]=ri[u]; sumv[now]=sumv[u]+1; if(l!=r){ if(L<=mid) le[now]=build(le[u],l,mid); else ri[now]=build(ri[u],mid+1,r); } return now; } void dfs(int u,int fr){ dep[u]=dep[fr]+1; f[u][0]=fr; if(!fa[u]) fa[u]=(fr?find(fr):u); siz[find(u)]++; L=a[u],rt[u]=build(rt[fr],1,ld); for(int i=1;i<17;i++) f[u][i]=f[f[u][i-1]][i-1]; for(int i=head[u];i;i=next[i]) if(to[i]!=fr) dfs(to[i],u); } void del(int u){if(!u || isin[u])return;qpush(u);del(le[u]);del(ri[u]);le[u]=ri[u]=0;} void shan(int u,int fr){ del(rt[u]); for(int i=head[u];i;i=next[i]) if(to[i]!=fr) shan(to[i],u); } int lca(int u,int v){ if(dep[u]<dep[v]) swap(u,v); for(int i=16;i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i]; if(u==v) return u; for(int i=16;i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; return f[u][0]; } void merge(int x,int y){ int a=find(x),b=find(y); if(siz[a]>siz[b]) swap(x,y),swap(a,b); fa[a]=b; siz[b]+=siz[a]; shan(a,0); link(x,y); dfs(x,y); } int query(int x,int y,int k){ int p=lca(x,y),l=1,r=ld,mid,now,g; x=rt[x]; y=rt[y]; g=rt[p]; while(l!=r){ mid=(l+r)>>1; now=(a[p]>=l && a[p]<=mid); now+=sumv[le[x]]+sumv[le[y]]-(sumv[le[g]]<<1); if(k<=now) r=mid,x=le[x],y=le[y],g=le[g]; else k-=now,l=mid+1,x=ri[x],y=ri[y],g=ri[g]; } return l; } int main(){ File("a"); getint(); n=getint(); m=getint(); T=getint(); for(int i=1;i<=n;i++) d[++ld]=a[i]=getint(); sort(d+1,d+ld+1); ld=unique(d+1,d+ld+1)-d-1; for(int i=1;i<=n;i++) a[i]=lower_bound(d+1,d+ld+1,a[i])-d; while(m--) link(getint(),getint()); for(int i=1;i<=n;i++) if(!dep[i]) dfs(i,0); while(T--){ char c=getchar(); int x,y; while(c!=‘Q‘ && c!=‘L‘) c=getchar(); x=getint()^lans,y=getint()^lans; if(c==‘L‘) merge(x,y); else printf("%d\n",lans=d[query(x,y,getint()^lans)]); } return 0; }
以上是关于BZOJ 3123 SDOI2013 森林的主要内容,如果未能解决你的问题,请参考以下文章
主席树 启发式合并bzoj3123: [Sdoi2013]森林