bzoj4881 [ Lydsy2017年5月月赛 ] -- 二分图染色+线段树
Posted gjghfd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4881 [ Lydsy2017年5月月赛 ] -- 二分图染色+线段树相关的知识,希望对你有一定的参考价值。
以下是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 [ Lydsy2017年5月月赛 ] -- 二分图染色+线段树的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4883[Lydsy2017年5月月赛]棋盘上的守卫 KM算法
BZOJ 4884 [Lydsy2017年5月月赛]太空猫(单调DP)
[bzoj4883][Lydsy2017年5月月赛]棋盘上的守卫
BZOJ 4883 [Lydsy2017年5月月赛]棋盘上的守卫(最小生成环套树森林)