zoukankan      html  css  js  c++  java
  • Codeforces 871C 872E Points, Lines and Ready-made Titles

      OvO http://codeforces.com/contest/871/problem/C

      ( Codeforces Round #440 (Div. 1, based on Technocup 2018 Elimination Round 2) - C )

      问题可以转化为:这些点可以产生的横线与竖线的出现情况

      首先,对于二维坐标系中的每一行中,对于每个点,如果右边有点,则从该点向右边这个点(相邻的那个点)连一条边(连一条单向的),

      对于每一列中,对于每个点,如果该点下面有点,则向下边这个点(相邻的那个点)连一条边(同上)

      (具体实现可以通过排序)

      然后对于每个点,将与之相连的点并查集合并,合并时如果发现成环,则这个集合tag=1,否则tag=0。

      算出每个集合中所有点所占据的不重复的行列数,记为dif。

      对于每个集合,如果这个集合中tag=1,那么这个集合所产生的答案为 2^dif,如果tag=0,那么这个集合所产生的答案为 (2^dif)-1 ,(原因的话,画图可以得出)

      每个集合的答案是独立的,所以取他们的积

      

      

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <set>
    #include <map>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N=4e5+44;
    const int mod=1e9+7;
    const int bas=1e9+44;
    
    struct node{
        int u,v;
        int next;
    } edge[2*N];
    
    struct Point
    {
    	int x,y,id;
    } p[N];
    
    int head[N],num,tag[N],cnt[N],dif[N];
    int n,ma[N];
    set<int> sx[N],sy[N];
    
    int findma(int x)
    {
    	if(ma[x]==x)
    		return x;
    	return ma[x]=findma(ma[x]);
    }
    
    bool cmp1(Point a,Point b)
    {
    	if(a.x==b.x)
    		return a.y<b.y;
    	return a.x<b.x;
    }
    
    bool cmp2(Point a,Point b)
    {
    	if(a.y==b.y)
    		return a.x<b.x;
    	return a.y<b.y;
    }
    
    bool cmp(Point a,Point b)
    {
    	return a.id<b.id;
    }
    
    
    void addedge(int u,int v)
    {
        edge[num].u=u;
        edge[num].v=v;
        edge[num].next=head[u];
        head[u]=num++;
    }
    
    void init()
    {
    	int i,j;
    	num=0;   
       	memset (head,-1,sizeof(head));
       	for(i=1;i<=n;i++)
       		ma[i]=i,cnt[i]=1;
       	memset(tag,0,sizeof(tag));
       	memset(dif,0,sizeof(dif));
       	for(i=1;i<=n;i++)
       		sx[i].clear(),sy[i].clear();;
    }
    
    long long pr(int a, int b)
    {
        long long r=1,base=a;
        while(b!=0)
        {
            if(b&1)
                r=(r*base)%mod;
            base=(base*base)%mod;
            b>>=1;
        }
        return r;
    }
    
    void solve()
    {
    	int i,j,a,b,pa,pb;
    	ll ans=1,tmp;
    	for(i=1;i<=n;i++)
    	{
    		for(j=head[i];j!=-1;j=edge[j].next)
    		{
    			a=i; b=edge[j].v;
    			pa=findma(a); pb=findma(b);
    			if(pa==pb)
    			{
    				tag[pa]=1;
    			}
    			else
    			{
    				ma[pa]=pb;
    				tag[pb]=tag[pb]|tag[pa];
    				cnt[pb]+=cnt[pa];
    			}
    		}
    	}
    	for(i=1;i<=n;i++)
    	{
    		a=i; pa=findma(a);
    		tmp=p[a].x;
    		if(sx[pa].find(tmp)==sx[pa].end())
    		{
    			dif[pa]++;
    			sx[pa].insert(tmp);
    		}
    		tmp=p[a].y;
    		if(sy[pa].find(tmp)==sy[pa].end())
    		{
    			dif[pa]++;
    			sy[pa].insert(tmp);
    		}
    	}
    	for(i=1;i<=n;i++)
    		if(ma[i]==i)
    		{
    			tmp=pr(2,dif[i]);
    			if(tag[i]==0) tmp--;
    			ans=ans*tmp%mod;
    		}
    	printf("%I64d
    ",ans);
    }
    
    int main()
    {
    	int i,j;
    	scanf("%d",&n);
    	init();
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d%d",&p[i].x,&p[i].y);
    		p[i].id=i;
    	}
    	sort(p+1,p+n+1,cmp1);
    	for(i=1;i<n;i++)
    		if(p[i].x==p[i+1].x)
    			addedge(p[i].id,p[i+1].id);
    	sort(p+1,p+n+1,cmp2);
    	for(i=1;i<n;i++)
    		if(p[i].y==p[i+1].y)
    			addedge(p[i].id,p[i+1].id);
    	sort(p+1,p+n+1,cmp);
    	solve();
    	return 0;
    }
    

      

  • 相关阅读:
    C#实现带阴历显示的日期代码
    ASP.NET实现支付宝接口功能
    网站添加手机短信功能
    ASP.NET支付宝扫码即时到账支付开发流程(序言)
    ASP.NET支付宝扫码即时到账支付开发流程(下)
    ASP.NET支付宝扫码即时到账支付开发流程(上)
    如何把自己写的程序加入到开机启动项(Windows)
    C#操作注册表
    重温SQL——行转列,列转行
    Unity Hub破解
  • 原文地址:https://www.cnblogs.com/FxxL/p/7673906.html
Copyright © 2011-2022 走看看