[IOI2018] werewolf 狼人 - 解題報告
阿新 • • 發佈:2018-12-23
題意:
有一張無向圖,一個人他需要從s走到t。
他有兩種形態,第一種形態可以走點編號為 \([ l_i,n ]\) ,第二種形態可以走點編號為 \([ 1,r_i ]\),可以點編號為 \([ l_i,n ]\)切換形態(恰好一次),在起點時為第一種形態。求他是否能從s走到t。
多組詢問。
題解:
首先我們可以維護與起點聯通的點集合(形態一),同時也可以維護維護與終點聯通的點集合(形態二),顯然可以用Kruskal重構樹維護。
用主席樹維護兩棵重構樹其中子樹是否有並集(二位數點)。
程式碼:
#include<bits/stdc++.h> using namespace std; const int N=400010; int n,m,q,fa[N],w[N]; vector <int> e[N]; int tot=0,rt[N],lf[N*25],rf[N*25],sum[N*25]; inline int read() { register int tmp=0;register char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') tmp=(tmp<<1)+(tmp<<3)+(c^48),c=getchar();return tmp; } //inline int Max(int x,int y) { return x>y? x:y; } //inline int Min(int x,int y) { return x<y? x:y; } int Find(int x) { return x==fa[x]? x:fa[x]=Find(fa[x]); } struct Kruskal { int type; int cnt,hed[N],to[N],nxt[N]; int tot,w[N],idx,dfn[N],bg[N],ed[N]; int st[N][20]; inline void add(int x,int y) { to[++cnt]=y,nxt[cnt]=hed[x],hed[x]=cnt; } void dfs(int u) { dfn[bg[u]=++idx]=u; for(int i=1;i<20;i++) st[u][i]=st[st[u][i-1]][i-1]; for(int i=hed[u];i;i=nxt[i]) dfs(to[i]); ed[u]=idx; } void build() { tot=n; for(int i=1;i<=n;++i) fa[i]=i; if(type) { for(int i=n;i;--i) for(int j=0;j<e[i].size();++j) if(i<e[i][j]) { int v=Find(e[i][j]); if(i==v) continue; add(i,v);fa[v]=st[v][0]=i; } dfs(1); } else { for(int i=1;i<=n;++i) for(int j=0;j<e[i].size();++j) if(i>e[i][j]) { int v=Find(e[i][j]); if(i==v) continue; add(i,v);fa[v]=st[v][0]=i; } dfs(n); } } inline int find(int u,int x) { for(int i=19;i>=0;i--) if(st[u][i]&&((type&&x<=st[u][i])||(!type&&x>=st[u][i]))) u=st[u][i]; return u; } };Kruskal mn,mx;// mn:people mx:wolf void update(int &u,int v,int l,int r,int x) { sum[u=++tot]=sum[v]+1,lf[u]=lf[v],rf[u]=rf[v]; if(l>=r) return ; int mid=(l+r)>>1; x<=mid? update(lf[u],lf[v],l,mid,x):update(rf[u],rf[v],mid+1,r,x); } int ask(int u,int v,int l,int r,int L,int R) { if(l==L&&r==R) return sum[v]-sum[u]; int mid=(l+r)>>1; if(R<=mid) return ask(lf[u],lf[v],l,mid,L,R); if(L>mid) return ask(rf[u],rf[v],mid+1,r,L,R); return ask(lf[u],lf[v],l,mid,L,mid)+ask(rf[u],rf[v],mid+1,r,mid+1,R); } int main() { n=read(),m=read(),q=read(); for(int i=1,x,y;i<=m;++i) x=read()+1,y=read()+1,e[x].push_back(y),e[y].push_back(x); mn.type=1,mn.build(),mx.build(); for(int i=1;i<=n;++i) w[mn.bg[i]]=mx.bg[i]; for(int i=1;i<=n;++i) update(rt[i],rt[i-1],1,n,w[i]); for(;q;--q) { int s=read()+1,t=read()+1,l=read()+1,r=read()+1; s=mn.find(s,l),t=mx.find(t,r); if(ask(rt[mn.bg[s]-1],rt[mn.ed[s]],1,n,mx.bg[t],mx.ed[t])) printf("1\n"); else printf("0\n"); } return 0; }