zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    MathType编辑半直积符号的步骤
    用几何画板演示涡旋电场的方法
    MathType编辑双向斜箭头的教程
    最实用的几何画板绘图技巧大总结
    怎么让Word编辑公式又快又好
    在几何画板中作三角形高的方法
    MathType中输入破折号的教程
    几何画板5.06最强中文版破解-下载-注册码
    如何通过几何画板来验证海伦公式
    如何用公式编辑器编辑直角三角形符号
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9107561.html
Copyright © 2011-2022 走看看