BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
2017-03-26 15:57
423 查看
3123: [Sdoi2013]森林
题意:一个森林,加边,询问路径上k小值。保证任意时刻是森林LCT没法搞,树上kth肯定要用树上主席树
加边?启发式合并就好了,小的树dfs重建一下
注意
测试点编号不是数据组数!!!
加边的时候要更新邻接链表啊,并且fa要清空
并查集维护size一定初始化1
好了现在我要填报名表了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; #define lc(x) t[x].l #define rc(x) t[x].r const int N=1e5+5, M=2e5+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n, m, Q, a , u, v, k, mp ; char s[5]; namespace ufs{ int fa , size ; int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);} } using ufs::size; using ufs::find; struct edge{int v,ne;}e[M]; int cnt, h ; inline void ins(int u, int v) { e[++cnt]=(edge){v, h[u]}; h[u]=cnt; e[++cnt]=(edge){u, h[v]}; h[v]=cnt; } int vis , fa [18], deep ; int lca(int x, int y) { if(deep[x]<deep[y]) swap(x, y); int bin=deep[x]-deep[y]; for(int i=0; i<17; i++) if((1<<i)&bin) x=fa[x][i]; if(x==y) return x; for(int i=16; i>=0; i--) if(fa[x][i] != fa[y][i]) x=fa[x][i], y=fa[y][i]; return fa[x][0]; } struct ChairTree{ struct meow{int l,r,size;}t[N*85]; int sz, root ; void insert(int &x, int l, int r, int p) { t[++sz]=t[x]; x=sz; t[x].size++; if(l==r) return; int mid=(l+r)>>1; if(p<=mid) insert(lc(x), l, mid, p); else insert(rc(x), mid+1, r, p); } void build(int u) { //printf("build %d %d\n",u,fa[u][0]); vis[u]=1; for(int i=1; (1<<i)<=deep[u]; i++) fa[u][i] = fa[ fa[u][i-1] ][i-1]; root[u] = root[fa[u][0]]; insert(root[u], 1, *mp, a[u]); for(int i=h[u];i;i=e[i].ne) if(e[i].v != fa[u][0]) { fa[e[i].v][0]=u; deep[e[i].v]=deep[u]+1; build(e[i].v); } } int query(int u, int v, int k) { int f=lca(u,v), g=fa[f][0]; int x=root[u], y=root[v], l=1, r=*mp; f=root[f]; g=root[g]; while(l!=r) { int lsize = t[lc(x)].size + t[lc(y)].size - t[lc(f)].size - t[lc(g)].size; int mid=(l+r)>>1; if(k<=lsize) x=lc(x), y=lc(y), f=lc(f), g=lc(g), r=mid; else x=rc(x), y=rc(y), f=rc(f), g=rc(g), l=mid+1, k-=lsize; } return l; } void rebuild(int u) { for(int i=1; i<17; i++) fa[u][i] = fa[ fa[u][i-1] ][i-1]; root[u] = root[fa[u][0]]; insert(root[u], 1, *mp, a[u]); for(int i=h[u];i;i=e[i].ne) if(e[i].v != fa[u][0]) { fa[e[i].v][0]=u; deep[e[i].v]=deep[u]+1; rebuild(e[i].v); } } void Link(int u, int v) { int x=find(u), y=find(v); if(size[x]<size[y]) swap(x, y), swap(u, v); ufs::fa[y]=x; size[x]+=size[y]; ins(u, v); fa[v][0]=u; deep[v]=deep[u]+1; rebuild(v); } }C; int candy; int main() { freopen("in","r",stdin); int T=read(); T+=2333; n=read(); m=read(); Q=read(); for(int i=1; i<=n; i++) a[i]=mp[i]=read(), ufs::fa[i]=i, size[i]=1; sort(mp+1, mp+1+n); mp[0]=unique(mp+1, mp+1+n)-mp-1; for(int i=1; i<=n; i++) a[i] = lower_bound(mp+1, mp+1+*mp, a[i])-mp; for(int i=1; i<=m; i++) { u=read(), v=read(); ins(u,v); u=find(u); v=find(v); ufs::fa[v]=u; size[u]+=size[v]; } for(int i=1; i<=n; i++) if(!vis[i]) C.build(i); int ans=0; //candy=1; for(int i=1; i<=Q; i++) { scanf("%s",s); if(candy) u=read(), v=read(); else u=read()^ans, v=read()^ans; if(s[0]=='Q') { if(candy) k=read(); else k=read()^ans; ans = mp[C.query(u, v, k)]; printf("%d\n", ans); }else C.Link(u, v); } }
相关文章推荐
- [BZOJ3123][Sdoi2013]森林(主席树启发式合并)
- BZOJ 3123: [Sdoi2013]森林 启发式合并 树上主席树
- Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)
- 【BZOJ3123】[Sdoi2013]森林 主席树+倍增LCA+启发式合并
- [BZOJ3123][Sdoi2013]森林(主席树+启发式合并)
- [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)
- 【bzoj3123】【sdoi2013】【森林】【启发式合并+主席树】
- [主席树 启发式合并] BZOJ 3123 [Sdoi2013]森林
- 【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并
- [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+倍增lca+启发式合并)
- [BZOJ3123][Sdoi2013]森林(主席树+启发式合并)
- BZOJ 3123: [Sdoi2013]森林|主席树|启发式合并
- bzoj 3123 [Sdoi2013]森林(主席树,lca,启发式合并)
- BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并
- [bzoj3123][Sdoi2013]森林_主席树_启发式合并
- BZOJ 3123 SDOI 2013 森林 可持久化线段树+启发式合并
- bzoj 3123: [Sdoi2013]森林 启发式合并+可持久化线段树
- 3123: [Sdoi2013]森林 主席树的启发式合并
- [luoguP3302] [SDOI2013]森林(主席树 + 启发式合并 + lca)
- 【BZOJ3123】森林(主席树,启发式合并)