[IOI2018] werewolf 狼人 - 解题报告

Posted daniel14311531

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[IOI2018] werewolf 狼人 - 解题报告相关的知识,希望对你有一定的参考价值。

题意:

有一张无向图,一个人他需要从s走到t。他有两种形态,第一种形态可以走点编号为 [ li,n],第二种形态可以走点编号为 [ 1,ri],可以点编号为 [ li,n]切换形态(恰好一次),在起点时为第一种形态。求他是否能从s走到t。多组询问。

 

题解:

首先我们可以维护与起点联通的点集合(形态一),同时也可以维护维护与终点联通的点集合(形态二),显然可以用Kruskal重构树维护。用主席树维护两棵重构树其中子树是否有并集(二位数点)。

 

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=400010;
 4 int n,m,q,fa[N],w[N];
 5 vector <int> e[N];
 6 int tot=0,rt[N],lf[N*25],rf[N*25],sum[N*25];
 7 
 8 inline int read() {
 9     register int tmp=0;register char c=getchar(); while(c<0||c>9)    c=getchar();
10     while(c>=0&&c<=9)    tmp=(tmp<<1)+(tmp<<3)+(c^48),c=getchar();return tmp;
11 }
12 //inline int Max(int x,int y) { return x>y?    x:y; }
13 //inline int Min(int x,int y) { return x<y?    x:y; }
14 int Find(int x) { return x==fa[x]?    x:fa[x]=Find(fa[x]); }
15 struct Kruskal {
16     int type;
17     int cnt,hed[N],to[N],nxt[N];
18     int tot,w[N],idx,dfn[N],bg[N],ed[N];
19     int st[N][20];
20     inline void add(int x,int y) { to[++cnt]=y,nxt[cnt]=hed[x],hed[x]=cnt; }
21     void dfs(int u) {
22         dfn[bg[u]=++idx]=u; for(int i=1;i<20;i++)    st[u][i]=st[st[u][i-1]][i-1];
23         for(int i=hed[u];i;i=nxt[i])    dfs(to[i]);
24         ed[u]=idx;
25     }
26     void build() {
27         tot=n; for(int i=1;i<=n;++i)    fa[i]=i;
28         if(type) {
29             for(int i=n;i;--i)
30                 for(int j=0;j<e[i].size();++j)
31                     if(i<e[i][j]) {
32                         int v=Find(e[i][j]); if(i==v)    continue;
33                         add(i,v);fa[v]=st[v][0]=i;
34                     }
35             dfs(1);
36         }
37         else {
38             for(int i=1;i<=n;++i)
39                 for(int j=0;j<e[i].size();++j)
40                     if(i>e[i][j]) {
41                         int v=Find(e[i][j]); if(i==v)    continue;
42                         add(i,v);fa[v]=st[v][0]=i;
43                     }
44             dfs(n);
45         }
46     }
47     inline int find(int u,int x) {
48         for(int i=19;i>=0;i--)
49             if(st[u][i]&&((type&&x<=st[u][i])||(!type&&x>=st[u][i])))
50                 u=st[u][i];
51         return u;
52     }
53 };Kruskal mn,mx;// mn:people   mx:wolf
54 
55 void update(int &u,int v,int l,int r,int x) {
56     sum[u=++tot]=sum[v]+1,lf[u]=lf[v],rf[u]=rf[v]; if(l>=r)    return ;
57     int mid=(l+r)>>1; x<=mid?    update(lf[u],lf[v],l,mid,x):update(rf[u],rf[v],mid+1,r,x);
58 }
59 int ask(int u,int v,int l,int r,int L,int R) {
60     if(l==L&&r==R)    return sum[v]-sum[u];
61     int mid=(l+r)>>1;
62     if(R<=mid)    return ask(lf[u],lf[v],l,mid,L,R);
63     if(L>mid)    return ask(rf[u],rf[v],mid+1,r,L,R);
64     return ask(lf[u],lf[v],l,mid,L,mid)+ask(rf[u],rf[v],mid+1,r,mid+1,R);
65 }
66 int main() {
67     n=read(),m=read(),q=read();
68     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);
69     mn.type=1,mn.build(),mx.build();
70     for(int i=1;i<=n;++i)    w[mn.bg[i]]=mx.bg[i];
71     for(int i=1;i<=n;++i)    update(rt[i],rt[i-1],1,n,w[i]);
72     for(;q;--q) {
73         int s=read()+1,t=read()+1,l=read()+1,r=read()+1;
74         s=mn.find(s,l),t=mx.find(t,r);
75         if(ask(rt[mn.bg[s]-1],rt[mn.ed[s]],1,n,mx.bg[t],mx.ed[t]))    printf("1
");
76         else    printf("0
");
77     }
78     return 0;
79 }

以上是关于[IOI2018] werewolf 狼人 - 解题报告的主要内容,如果未能解决你的问题,请参考以下文章

p4899 [IOI2018] werewolf 狼人

[IOI2018] werewolf 狼人 - 解题报告

[IOI2018] werewolf 狼人 - 解题报告

[IOI2018]werewolf狼人——kruskal重构树+可持久化线段树

[IOI 2018] Werewolf

Luogu4899 IOI2018 Werewolf 主席树Kruskal重构树