「JOISC 2017 Day 1」港口设施
Solution
可以看出对于两个点 \((a,b),(c,d)\),如果存在 \(a<c<b<d\),那么两者就不能在同一个栈。所以我们可以把这种关系连边,无解即是存在奇环,否则答案就是 \(2\) 的连通块个树次方。
似乎可以直接动态开点线段树优化建图?但是还有一种比较优美的做法。
考虑如何优化连边。我们按 \(b_i\) 排序之后加进去,每一次考虑到 \((a_i,b_i)\) 即是往未被加进去且左端点在 \((a_i,b_i)\) 的点进行连边。但是这样边数还是很大。
我们可以发现的是,对于这个区间的点,它们的颜色应该是一样的,而颜色一样的我们显然可以并起来往其中一个点连边即可,所以我们可以考虑并查集维护一个点最远的同颜色段。加没加入也可以用并查集进行维护。
复杂度显然是 \(\Theta(n\log n)\) 的。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define mod 1000000007
#define MAXN 2000005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
int n,m,a[MAXN],b[MAXN],ql[MAXN],fa[MAXN],nxt[MAXN],col[MAXN];
int findSet (int x){return fa[x] == x ? x : fa[x] = findSet (fa[x]);}
vector <int> H[MAXN];
void linkit (int u,int v){H[u].push_back (v),H[v].push_back (u);}
bool dfs (int u,int c){
if (col[u] != -1 && col[u] != c) return 0;
if (col[u] != -1) return 1;
col[u] = c;
for (Int v : H[u]) if (!dfs (v,c ^ 1)) return 0;
return 1;
}
signed main(){
read (n);
for (Int i = 1,x,y;i <= n;++ i) read (x,y),b[x] = b[y] = i;
for (Int x = 1;x <= n * 2;++ x) fa[x] = nxt[x] = x;
for (Int i = 1;i <= 2 * n;++ i){
int t = b[i];
if (!ql[t]){a[++ m] = t,ql[t] = m;continue;}
for (Int j = fa[ql[t]] = findSet (ql[t] + 1);j <= m;){
linkit (a[j],t);
int u = findSet (nxt[j] + 1);
nxt[j] = m,j = u;
}
}
memset (col,-1,sizeof (col));
int tot = 0,ans = 1;
for (Int x = 1;x <= n;++ x) if (col[x] == -1){
if (!dfs (x,0)) return puts ("0") & 0;
else tot ++;
}
for (Int i = 1;i <= tot;++ i) ans = ans * 2 % mod;
write (ans),putchar ('\n');
return 0;
}