UOJ#407. 【IOI2018】狼人 Kruskal,kruskal重构树,主席树
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ407.html
题解
套路啊。
先按照两个节点顺序各搞一个kruskal重构树,然后问题转化成两棵kruskal重构树,不断询问,每次询问让你判断是否有点同时存在于 第一棵树的一个子树 和 第二棵树的一个子树中。
这个东西就转成dfs序之后主席树搞一搞就好了。
代码
#include <bits/stdc++.h> #include "werewolf.h" #define clr(x) memset(x,0,sizeof (x)) #define y1 __zzd001 using namespace std; typedef vector <int> vi; const int N=400005; int n,m,q; vi e[N],ans,tmp; namespace ufs{ int fa[N]; void init(int n){ for (int i=1;i<=n;i++) fa[i]=i; } int getf(int x){ return fa[x]==x?x:fa[x]=getf(fa[x]); } } struct ktree{ int val[N],son[N][2],fa[N][20]; int I[N],O[N],vis[N]; int cnt,root,Time; void dfs(int x){ if (!x) return; I[x]=++Time; for (int i=1;i<20;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; dfs(son[x][0]); dfs(son[x][1]); O[x]=Time; } void build(vi ord){ clr(val),clr(son),clr(fa),clr(vis); cnt=n; ufs::init(n*2); for (auto x : ord){ val[x]=x,vis[x]=1; for (auto y : e[x]){ if (!vis[y]) continue; int fx=ufs::getf(x),fy=ufs::getf(y); if (fx==fy) continue; val[++cnt]=x; ufs::fa[fx]=ufs::fa[fy]=fa[fx][0]=fa[fy][0]=cnt; son[cnt][0]=fx,son[cnt][1]=fy; } } for (root=1;fa[root][0];root=fa[root][0]); Time=0; dfs(root); } }t1,t2; int c1,c2; namespace pt{ const int S=N*40; int val[S],ls[S],rs[S],root[N],cnt,m; int build(int L,int R){ int rt=++cnt; if (L==R) return rt; int mid=(L+R)>>1; ls[rt]=build(L,mid); rs[rt]=build(mid+1,R); return rt; } void init(int _m){ clr(val),clr(ls),clr(rs),clr(root),cnt=0; root[0]=build(1,m=_m); } void update(int prt,int &rt,int L,int R,int x){ if (!rt||rt==prt) rt=++cnt,val[rt]=val[prt],ls[rt]=ls[prt],rs[rt]=rs[prt]; val[rt]++; if (L==R) return; int mid=(L+R)>>1; if (x<=mid) update(ls[prt],ls[rt],L,mid,x); else update(rs[prt],rs[rt],mid+1,R,x); } int Query(int prt,int rt,int L,int R,int xL,int xR){ if (xR<L||R<xL) return 0; if (xL<=L&&R<=xR) return val[rt]-val[prt]; int mid=(L+R)>>1; return Query(ls[prt],ls[rt],L,mid,xL,xR) +Query(rs[prt],rs[rt],mid+1,R,xL,xR); } int Query(int x1,int x2,int y1,int y2){ return Query(root[x1-1],root[x2],1,m,y1,y2); } } vi check_validity(int n,vi X,vi Y,vi S,vi E,vi L,vi R){ ::n=n,m=(int)X.size(),q=(int)S.size(),ans.clear(); for (int i=0;i<m;i++) X[i]++,Y[i]++; for (int i=0;i<q;i++) S[i]++,E[i]++,L[i]++,R[i]++; for (int i=1;i<=n;i++) e[i].clear(); for (int i=0;i<m;i++){ e[X[i]].push_back(Y[i]); e[Y[i]].push_back(X[i]); } tmp.clear(); for (int i=1;i<=n;i++) tmp.push_back(i); t1.build(tmp),t1.val[0]=1e9; reverse(tmp.begin(),tmp.end()); t2.build(tmp),t2.val[0]=-1e9; c1=t1.cnt,c2=t2.cnt; tmp.resize(c1+1); for (int i=1;i<=c1;i++) tmp[t1.I[i]]=i; pt::init(c2); for (int i=1;i<=c1;i++){ int x=tmp[i]; pt::root[i]=pt::root[i-1]; if (x<=n) pt::update(pt::root[i-1],pt::root[i],1,pt::m,t2.I[x]); } for (int i=0;i<q;i++){ int x=S[i],y=E[i],l=L[i],r=R[i]; if (x<l||y>r){ ans.push_back(0); continue; } for (int i=19;i>=0;i--){ if (t2.val[t2.fa[x][i]]>=l) x=t2.fa[x][i]; if (t1.val[t1.fa[y][i]]<=r) y=t1.fa[y][i]; } int t=pt::Query(t1.I[y],t1.O[y],t2.I[x],t2.O[x]); ans.push_back(t?1:0); } return ans; }