[BZOJ3123][Sdoi2013]森林(主席树启发式合并)
2016-12-15 16:42
555 查看
题目描述
传送门题解
主席树的启发式合并裸题?坑点:
①强制在线,但是我刚开始的时候ans里存的并不是答案,而是离散化之后的值,gg。
②合并的时候lca数组要完全清空。
代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> using namespace std; #define N 100005 #define lg 17 int T,n,m,q,x,y,k,s,t,sz,ans; int tot,point ,nxt[N*2],v[N*2]; int a ,b ; int ufs ,size ,h ,f [lg+5]; int root ,sum[N*200],ls[N*200],rs[N*200]; bool vis ; int lsh(int x) { int l=1,r=b[0],mid,ans; while (l<=r) { mid=(l+r)>>1; if (b[mid]>=x) ans=mid,r=mid-1; else l=mid+1; } return ans; } int find(int x) { if (ufs[x]==x) return x; ufs[x]=find(ufs[x]); return ufs[x]; } void add(int x,int y) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; } void update(int &now,int l,int r,int x) { int mid=(l+r)>>1; sum[++sz]=sum[now]+1,ls[sz]=ls[now],rs[sz]=rs[now];now=sz; if (l==r) return; if (x<=mid) update(ls[now],l,mid,x); else update(rs[now],mid+1,r,x); } int query(int x,int y,int s,int t,int l,int r,int k) { int mid=(l+r)>>1; if (l==r) return l; int tmp=sum[ls[x]]+sum[ls[y]]-sum[ls[s]]-sum[ls[t]]; if (tmp>=k) return query(ls[x],ls[y],ls[s],ls[t],l,mid,k); else return query(rs[x],rs[y],rs[s],rs[t],mid+1,r,k-tmp); } void build(int x,int fa) { vis[x]=true; h[x]=h[fa]+1; root[x]=root[fa]; update(root[x],1,b[0],a[x]); for (int i=1;i<lg;++i) { if (h[x]-(1<<i)<1) break; f[x][i]=f[f[x][i-1]][i-1]; } for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa) { int f1=find(x),f2=find(v[i]); ufs[f2]=f1;size[f1]+=size[f2]; f[v[i]][0]=x; build(v[i],x); } } int lca(int x,int y) { if (h[x]<h[y]) swap(x,y); int k=h[x]-h[y]; for (int i=0;i<lg;++i) if ((k>>i)&1) x=f[x][i]; if (x==y) return x; for (int i=lg-1;i>=0;--i) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } void rebuild(int x,int fa) { h[x]=h[fa]+1; root[x]=root[fa]; update(root[x],1,b[0],a[x]); for (int i=1;i<lg;++i) { // if (h[x]-(1<<i)<1) break; f[x][i]=f[f[x][i-1]][i-1]; } for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa) { f[v[i]][0]=x; rebuild(v[i],x); } } int main() { scanf("%d",&T); scanf("%d%d%d",&n,&m,&q); for (int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1); b[0]=unique(b+1,b+n+1)-b-1; for (int i=1;i<=n;++i) a[i]=lsh(a[i]); for (int i=1;i<=m;++i) { scanf("%d%d",&x,&y); add(x,y);add(y,x); } for (int i=1;i<=n;++i) ufs[i]=i,size[i]=1; for (int i=1;i<=n;++i) if (!vis[i]) build(i,0); for (int i=1;i<=q;++i) { char opt=getchar(); while (opt!='L'&&opt!='Q') opt=getchar(); if (opt=='Q') { scanf("%d%d%d",&x,&y,&k); x^=ans,y^=ans,k^=ans; s=lca(x,y);t=f[s][0]; ans=query(root[x],root[y],root[s],root[t],1,b[0],k); ans=b[ans]; printf("%d\n",ans); } else { scanf("%d%d",&x,&y); x^=ans,y^=ans; int f1=find(x),f2=find(y); if (size[f1]>size[f2]) swap(x,y),swap(f1,f2); f[x][0]=y;rebuild(x,y);add(x,y);add(y,x); ufs[f1]=f2;size[f2]+=size[f1]; } } }
总结
相关文章推荐
- Tinker接入
- 海龟git操作教程
- socket状态查看
- elasticsearch-jdbc实现MySQL同步到ElasticSearch深入详解
- Spring的作用域以及RequestContextListener作用
- 第十五周 将字符串格式化后输出
- firefox出现连接不安全
- 一种多尺度的KCF跟踪程序代码分析(一)
- [Java]详解Socket和ServerSocket学习笔记
- C# winform写入和读取TXT文件
- Log4j的进阶使用 自定义类 日志类型 日志导出位置
- hpfeeds操作
- spring+hibernate+jta 分布式事务Demo
- 百度地图画出手机GPS行驶轨迹——Web端
- 基本概念学习(9000)---查看端口号是否被占用
- Android Fragment 的使用,一些你不可不知的注意事项
- [BZOJ3166][Heoi2013]Alo(可持久化线段树+可持久化tire树)
- 单例模式
- 博为峰Java技术题 ——JavaSE Java Swing顶层容器类和包含层次Ⅱ
- Android ProGuard 混淆 详解