[BZOJ5288][HNOI2018]游戏(拓扑排序)

Posted HocRiser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ5288][HNOI2018]游戏(拓扑排序)相关的知识,希望对你有一定的参考价值。

传送门:https://www.luogu.org/problemnew/show/P4436

20分的暴力加一个Random_shuffle就A了。我还能说什么。。

不过这个也不是毫无道理,复杂度应该是期望$O(n\log n)$的。

这件事教导我们在写暴力之前先Random_shuffle一下总没错。。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 typedef long long ll;
 5 using namespace std;
 6 
 7 const int N=1000100;
 8 int n,x,y,a[N],L[N],R[N],m,Q,p[N];
 9 
10 void solve(int x){
11     int l=x,r=x;
12     while (1){
13         bool flag=0;
14         if (l>1 && ((l<=a[l-1] && a[l-1]<=r) || !a[l-1]))
15             flag=1,l--,l=min(l,L[l]),r=max(r,R[l]);
16         if (r<n && ((l<=a[r] && a[r]<=r) || !a[r]))
17             flag=1,r++,l=min(l,L[r]),r=max(r,R[r]);
18         if (!flag) break;
19     }
20     L[x]=l; R[x]=r;
21 }
22 
23 int main(){
24     freopen("bzoj5288.in","r",stdin);
25     freopen("bzoj5288.out","w",stdout);
26     srand(20020223); scanf("%d%d%d",&n,&m,&Q);
27     rep(i,1,m) scanf("%d%d",&x,&y),a[x]=y;
28     rep(i,1,n) L[i]=n+1;
29     rep(i,1,n) p[i]=i;
30     random_shuffle(p+1,p+n+1);
31     rep(i,1,n) solve(p[i]);
32     while (Q--){
33         scanf("%d%d",&x,&y);
34         if (L[x]<=y && y<=R[x]) puts("YES"); else puts("NO");
35     }
36     return 0;
37 }

下面是靠谱一点的做法。将点离散化,考虑一个区间,如果它的钥匙在区间左边,则显然必须先处理后一个区间的信息再去处理当前区间的信息(方便合并),所以连边i+1->i,反之同理。

按照拓扑序处理信息即可,每个区间最多只会和左边合并一次,右边和合并一次,所以总复杂度$O(n)$。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 using namespace std;
 5 
 6 const int N=1000010;
 7 int n,m,p,x,y,s,t,lock[N],len,top,cnt,to[N],nxt[N],h[N];
 8 int key[N],deg[N],bel[N],beg[N],end[N],pos[N],L[N],R[N],q[N<<2];
 9 
10 void ins(int x,int y){ to[++len]=y; nxt[len]=h[x]; h[x]=len; }
11 void inc(int &x){ x++; if (x>N) x-=N; }
12 
13 void pre(){
14     int st=0,ed=0;
15     rep(i,1,cnt) if (!deg[i]) q[++ed]=i;
16     while (st!=ed){
17         inc(st); int x=q[st];
18         while (1){
19             int flag=0;
20             if (L[x]>1 && pos[L[x]-1]>=L[x] && pos[L[x]-1]<=R[x]) L[x]=L[L[x]-1],flag=1;
21             if (R[x]<cnt && pos[R[x]]>=L[x] && pos[R[x]]<=R[x]) R[x]=R[R[x]+1],flag=1;
22             if (!flag) break;
23         }
24         for (int i=h[x]; i; i=nxt[i]){
25             int y=to[i]; deg[y]--;
26             if (!deg[y]) inc(ed),q[ed]=y;
27         }
28     }
29 }
30 
31 int main(){
32     freopen("bzoj5288.in","r",stdin);
33     freopen("bzoj5288.out","w",stdout);
34     scanf("%d%d%d",&n,&m,&p); lock[0]=1;
35     rep(i,1,m) scanf("%d%d",&x,&y),lock[x]=1,key[x]=y;
36     rep(i,1,n){
37         if (lock[i-1]) cnt++;
38         bel[i]=cnt; end[cnt]=i;
39         if (!beg[cnt]) beg[cnt]=i;
40     }
41     rep(i,1,cnt-1){
42         pos[i]=bel[key[end[i]]];
43         if (pos[i]<=i) ins(i+1,i),deg[i]++; else ins(i,i+1),deg[i+1]++;
44     }
45     rep(i,1,n) L[i]=R[i]=i; pre();
46     while (p--){
47         scanf("%d%d",&s,&t);
48         if (L[bel[s]]<=bel[t] && bel[t]<=R[bel[s]]) puts("YES"); else puts("NO");
49     }
50     return 0;
51 }

 

以上是关于[BZOJ5288][HNOI2018]游戏(拓扑排序)的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ5289][HNOI2018]排列(拓扑排序+pb_ds)

bzoj千题计划310:bzoj5285: [Hnoi2018]寻宝游戏(思维题+哈希)

拓扑排序BZOJ4010-[HNOI2015]菜肴制作

BZOJ4010[HNOI2015]菜肴制作 拓扑排序

BZOJ4010 HNOI2015 菜肴制作 拓扑排序+贪心

bzoj4010: [HNOI2015]菜肴制作(拓扑排序+贪心+堆)