1. 程式人生 > >bzoj4881 [ Lydsy2017年5月月賽 ] -- 二分圖染色+線段樹

bzoj4881 [ Lydsy2017年5月月賽 ] -- 二分圖染色+線段樹

splay 最大的 include alt sed string cstring pan 最小

以下是Claris的題解:

若線段 i j 相交,那麽在它們之間連一條邊。若這個圖不是二分圖,那麽無解,否則令cnt 為連通塊個數,那麽 ans = 2cnt

在二分圖染色的過程中,每個點只需要被訪問一次。對於當前所在的點 x,它可以一步走到 [1, x) 裏 p[i] > p[x] 的所有 i,以及 (x, n] 裏 p[j] < p[x] 的所有 j。

用線段樹維護所有沒走過的點,記錄每個區間 p 最小與最大的兩個位置。每次貪心取出最大/小的,看看是否滿足條件,

若滿足則刪除該點,然後遞歸染色,否則終止。
時間復雜度 O(n log n)。

代碼:

技術分享
 1 #include<iostream>
 2
#include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define N 100010 7 #define M 998244353 8 #define INF 1000000 9 int i,j,k,n,m,p[N],c[2][N<<2],s[2][N<<2],Cnt,f[2]; 10 bool a[N],v[N]; 11 inline int Min(int x,int y){return x<y?x:y;} 12 inline int
Max(int x,int y){return x<y?y:x;} 13 inline void Up(int Node){ 14 c[0][Node]=Min(c[0][Node<<1],c[0][Node<<1|1]); 15 s[0][Node]=c[0][Node]==c[0][Node<<1]?s[0][Node<<1]:s[0][Node<<1|1]; 16 c[1][Node]=Max(c[1][Node<<1],c[1][Node<<1|1]); 17 s[1][Node]=c[1
][Node]==c[1][Node<<1]?s[1][Node<<1]:s[1][Node<<1|1]; 18 } 19 inline void Update(int Node,int l,int r,int x){ 20 if(l==r){ 21 c[0][Node]=INF; 22 c[1][Node]=s[0][Node]=s[1][Node]=0; 23 return; 24 } 25 int Mid=l+r>>1; 26 if(x<=Mid)Update(Node<<1,l,Mid,x);else Update(Node<<1|1,Mid+1,r,x); 27 Up(Node); 28 } 29 inline int Query(int Node,int l,int r,int L,int R,bool d){ 30 if(l>=L&&r<=R)return s[d][Node]; 31 int Mid=l+r>>1; 32 if(Mid<L)return Query(Node<<1|1,Mid+1,r,L,R,d); 33 if(Mid>=R)return Query(Node<<1,l,Mid,L,R,d); 34 int Q1=Query(Node<<1,l,Mid,L,R,d),Q2=Query(Node<<1|1,Mid+1,r,L,R,d); 35 if(Q1&&(d^(p[Q1]<p[Q2]?1:0)))return Q1;return Q2; 36 } 37 inline void Dfs(int x){ 38 v[x]=1; 39 Update(1,1,n,x); 40 while(1){ 41 if(x>1){ 42 int y=Query(1,1,n,1,x-1,1); 43 if(y&&p[y]>p[x]){ 44 a[y]=a[x]^1; 45 Dfs(y); 46 continue; 47 } 48 } 49 if(x<n){ 50 int y=Query(1,1,n,x+1,n,0); 51 if(y&&p[y]<p[x]){ 52 a[y]=a[x]^1; 53 Dfs(y); 54 continue; 55 } 56 } 57 break; 58 } 59 } 60 inline int Pow(int x,int y){ 61 if(y==0)return 1; 62 int Ans=Pow(x,y>>1); 63 Ans=1ll*Ans*Ans%M; 64 if(y&1)Ans=1ll*Ans*x%M; 65 return Ans; 66 } 67 inline void Build(int Node,int l,int r){ 68 if(l==r){ 69 scanf("%d",&p[l]); 70 c[0][Node]=c[1][Node]=p[l]; 71 s[0][Node]=s[1][Node]=l; 72 return; 73 } 74 int Mid=l+r>>1; 75 Build(Node<<1,l,Mid); 76 Build(Node<<1|1,Mid+1,r); 77 Up(Node); 78 } 79 int main(){ 80 scanf("%d",&n); 81 Build(1,1,n); 82 for(i=1;i<=n;i++) 83 if(!v[i])a[i]=1,Dfs(i),Cnt++; 84 for(i=1;i<=n;i++) 85 if(f[a[i]]>p[i]){puts("0");return 0;}else f[a[i]]=p[i]; 86 printf("%d\n",Pow(2,Cnt)); 87 return 0; 88 }
bzoj4881

bzoj4881 [ Lydsy2017年5月月賽 ] -- 二分圖染色+線段樹