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

 


以上是关于bzoj4881 [ Lydsy2017年5月月赛 ] -- 二分图染色+线段树的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4883[Lydsy2017年5月月赛]棋盘上的守卫 KM算法

BZOJ 4884 [Lydsy2017年5月月赛]太空猫(单调DP)

[bzoj4883][Lydsy2017年5月月赛]棋盘上的守卫

BZOJ 4883 [Lydsy2017年5月月赛]棋盘上的守卫(最小生成环套树森林)

[Bzoj4832][Lydsy2017年4月月赛]抵制克苏恩 (期望dp)

bzoj 4836: [Lydsy2017年4月月赛]二元运算 -- 分治+FFT