[BZOJ5288][HNOI2018]遊戲(拓撲排序)
阿新 • • 發佈:2018-04-27
bsp fin www 應該 using dom open 離散 end
傳送門: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 usingnamespace 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]遊戲(拓撲排序)