UOJ #356. 【JOI2017春季合宿】Port Facility

Description

小M有兩個本質不同的棧。
無聊的小M找來了n個玩具。之後小M把這n個玩具隨機順序加入某一個棧或把他們彈出。
現在小M告訴你每個玩具的入棧和出棧時間,現在她想考考小S,有多少種方案,把每個玩具分配給兩個棧之一,並且存在一種滿足小M告訴你的入棧和出棧時間的入棧序列。
可憐的小S當然不知道啦,所以他求助於你。

Solution

考慮把存在矛盾的玩具連邊,設 \(k\) 是最後的連通塊數,如果這個圖是二分圖,那麼答案就是 \(2^{k}\)
這樣連邊是 \(O(n^2)\) 的,考慮優化連邊
按找 \(l\) 排序之後,前面訪問過的區間的 \(r\) 丟入一個 \(set\) 裏面,那麼與這個區間相交的區間是 \(set\) 中的一個區間
我們要把這個區間內的邊都向這個點連邊,我們加一個優化:
我們把區間內的點向兩邊的點連 \(0\)
區間的兩個端點向這個區間連 \(1\)
如果一個點被兩邊都連了 \(0\) 邊,那麼可以把這個點刪去
最後二分圖染色一下,順便算一下連通塊個數就好了

#include<bits/stdc++.h>
using namespace std;
template<class T>void gi(T &x){
    int f;char c;
    for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=2e5+10,mod=1e9+7;
struct data{
    int l,r;
    inline bool operator <(const data &p)const{return l<p.l;}
}e[N];
set<int>S,V;
set<int>::iterator it,st[N];
int n,L[N],R[N],head[N],nxt[N*4],to[N*4],num=0,dis[N*4],b[N],top=0,vis[N];
inline void link(int x,int y,int z){
    x=b[x];y=b[y];
    nxt[++num]=head[x];to[num]=y;head[x]=num;dis[num]=z;
    nxt[++num]=head[y];to[num]=x;head[y]=num;dis[num]=z;
}
inline void dfs(int x){
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        if(vis[u]){
            if(vis[u]!=(vis[x]^dis[i]))puts("0"),exit(0);
            continue;
        }
        else vis[u]=vis[x]^dis[i],dfs(u);
    }
}
int main(){
  freopen("port.in","r",stdin);
  freopen("port.out","w",stdout);
  cin>>n;
  for(int i=1;i<=n;i++)gi(e[i].l),gi(e[i].r),b[e[i].r]=i;
  sort(e+1,e+n+1);
  S.insert(mod);S.insert(-mod);
  V.insert(mod);V.insert(-mod);
  for(int i=1;i<=n;i++){
      int x=e[i].l,y=e[i].r;
      it=S.upper_bound(y);
      R[y]=*it;L[y]=*(--it);
      if(*it>x)link(y,*it,3);
      for(it=--V.upper_bound(y);*it>x;--it){
          if(L[*it]>x)link(*it,L[*it],0),L[*it]=-mod;
          if(R[*it]<y)link(*it,R[*it],0),R[*it]=mod;
          if(L[*it]==-mod && R[*it]==mod)st[++top]=it;
      }
      while(top)V.erase(st[top--]);
      S.insert(y);V.insert(y);
  }
  int ans=1;
  for(int i=1;i<=n;i++)
      if(!vis[i])vis[i]=1,dfs(i),ans=ans*2%mod;
  cout<<ans<<endl;
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章