• LOJ#2052. 「HNOI2016」矿区(对偶图)


    题目描述


    平面图&对偶图

    平面图的定义:可以放在笛卡尔坐标系中,边只会在给定顶点处相交

    把平面图中的每个区域+无穷域当作一个点,每条边变成两边的区域的连边,即为对偶图

    把一条边拆成两条,每次找一个点,对于一条边找逆时针的下一条边(总方向是顺时针),直到找出一个环

    因此要找一个块的内侧就可以按照上面的顺序寻找,找到的边所对应的块即为内侧

    从u--v中u在v中的编号可以排序+二分,每条边只会经过一次

    对于最小割可以把源汇连起来作为一个新的区域,从该块到无穷域的最短路即为最小割

    题解

    总面积很好求,问题是怎么求面积的平方和

    把对偶图建一棵生成树,以无穷域为根统计子树和

    无穷域找法:可以先判掉最外圈,具体为找y最大的点,然后逆时针寻找

    也可以直接找面积为负的区域

    如果一个询问经过的边不在生成树上就不管,如果内侧块(即当前边所对应的块,在顺时针方向)在生成树上为儿子就加上答案,否则减去答案

    画一下就可以发现这样是对的

    注意题目给出询问点是逆时针,所以要反过来

    code

    很好写(3.7k)

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    //#define file
    using namespace std;
    
    struct p{
    	int x,y;
    } a[200001];
    struct type{
    	int x,y;
    	double s;
    } b[1200001];
    struct Type{
    	int x,id;
    } B[1200001];
    int aa[800001][2];
    int ls[400002];
    bool bz[1200001];
    int c[1200001];
    int C[1200001];
    int st[200002];
    long long S[400002];
    long long S2[400002];
    int fa[400002];
    int FA[400002];
    int q[200002];
    int n,m,Q,i,j,k,l,K,L,tot,N,Tot,mx,mx2,len,x,X,y;
    long long lsans,ans1,ans2,Gcd;
    char ch;
    
    void New(int x,int y)
    {
    	++len;
    	aa[len][0]=y;
    	aa[len][1]=ls[x];
    	ls[x]=len;
    }
    
    int getint()
    {
    	int x=0,k=1;
    	
    	ch=getchar();
    	while (ch<'0' || ch>'9') k=(ch=='-')?-1:k,ch=getchar();
    	while (ch>='0' && ch<='9') x=x*10+(ch-'0'),ch=getchar();
    	
    	return x*k;
    }
    
    long long cj(p a,p b)
    {
    	return b.x*a.y-a.x*b.y;
    }
    
    bool cmp(type a,type b) {return a.x<b.x || a.x==b.x && a.s<b.s;}
    bool Cmp(Type a,Type b) {return a.x<b.x;}
    
    double ang(p a,p b)
    {
    	int x=b.x-a.x,y=b.y-a.y;
    	
    	if (!y)
    	{
    		if (x>0)
    		return 0;
    		return M_PI;
    	}
    	if (!x)
    	{
    		if (y>0)
    		return M_PI/2;
    		return M_PI*3/2;
    	}
    	
    	if (x>0 && y>0) return atan(1.0*y/x);
    	if (x>0 && y<0) return atan(1.0*y/x)+M_PI*2;
    	return atan(1.0*y/x)+M_PI;
    }
    
    long long gcd(long long a,long long b)
    {
    	long long r=a%b;
    	
    	while (r)
    	a=b,b=r,r=a%b;
    	
    	return b;
    }
    
    int find(int t,int x)
    {
    	int l=st[t],r=st[t+1]-1,mid;
    	
    	while (l<r)
    	{
    		mid=(l+r)/2;
    		
    		if (B[mid].x<x)
    		l=mid+1;
    		else
    		r=mid;
    	}
    	
    	return B[l].id;
    }
    
    void work(int k,int l)
    {
    	int K,L;
    	
    	while (!bz[l])
    	{
    		S[N]+=cj(a[k],a[b[l].y]);
    		
    		bz[l]=1;
    		c[l]=N;
    		
    		K=b[l].y;
    		L=find(K,k);
    		if (L==st[K+1]-1)
    		L=st[K];
    		else
    		++L;
    		
    		k=K,l=L;
    	}
    	S2[N]=S[N]*S[N];
    }
    
    int gf(int t)
    {
    	if (fa[t]==t) return t;
    	fa[t]=gf(fa[t]);
    	return fa[t];
    }
    
    void dfs(int Fa,int t)
    {
    	int i;
    	FA[t]=Fa;
    	
    	for (i=ls[t]; i; i=aa[i][1])
    	if (aa[i][0]!=Fa)
    	{
    		dfs(t,aa[i][0]);
    		S2[t]+=S2[aa[i][0]];
    	}
    }
    
    int main()
    {
    	#ifdef file
    	freopen("loj2052_8.in","r",stdin);
    	#endif
    	
    	n=getint();m=getint();Q=getint();
    	fo(i,1,n)
    	a[i].x=getint(),a[i].y=getint();
    	fo(i,1,m)
    	{
    		j=getint(),k=getint();
    		
    		b[++tot]={j,k,ang(a[j],a[k])};
    		b[++tot]={k,j,ang(a[k],a[j])};
    	}
    	
    	sort(b+1,b+tot+1,cmp);
    	fo(i,1,tot) B[i]={b[i].y,i};
    	
    	j=1;
    	fo(i,1,n)
    	{
    		st[i]=j;
    		while (j<=tot && b[j].x==i)
    		++j;
    	}
    	st[n+1]=tot+1;
    	
    	fo(i,1,n)
    	if (st[i]<st[i+1])
    	sort(B+st[i],B+(st[i+1]-1)+1,Cmp);
    	
    //	---外边界
    	
    	mx=-2133333333;
    	fo(i,1,n)
    	if (a[i].y>mx)
    	mx=a[i].y,mx2=i;
    	
    	N=1;
    	fo(j,st[mx2],st[mx2+1]-1)
    	if (b[j].s>=M_PI-0.00000001)
    	{
    		work(mx2,j);
    		break;
    	}
    	
    //	---对偶图
    	
    	fo(i,1,n)
    	{
    		fo(j,st[i],st[i+1]-1)
    		if (!bz[j])
    		{
    			++N;
    			work(i,j);
    		}
    	}
    	fo(i,1,N) fa[i]=i;
    	
    //	---生成树
    	
    	fo(i,1,n)
    	{
    		fo(j,st[i],st[i+1]-1)
    		{
    			k=find(b[j].y,i);
    			C[j]=c[k];
    			
    			if (gf(c[j])!=gf(c[k]))
    			{
    				fa[fa[c[j]]]=fa[c[k]];
    				bz[j]=bz[k]=0;
    				
    				New(c[j],c[k]);
    				New(c[k],c[j]);
    			}
    		}
    	}
    	dfs(0,1);
    	
    //	---
    	
    	for (;Q;--Q)
    	{
    		lsans=ans1,ans1=ans2=0;
    		Tot=getint();Tot=(Tot+lsans%n)%n+1;
    		fo(i,1,Tot) q[i]=getint(),q[i]=(q[i]+lsans%n)%n+1;
    		
    		fd(i,Tot,1)
    		{
    			j=find(q[i%Tot+1],q[i]);
    			
    			if (!bz[j])
    			{
    				if (FA[c[j]]==C[j])
    				ans1+=S2[c[j]];
    				else
    				if (FA[C[j]]==c[j])
    				ans1-=S2[C[j]];
    			}
    			ans2+=cj(a[q[i%Tot+1]],a[q[i]]);
    		}
    		
    		ans2*=2;
    		Gcd=gcd(ans1,ans2);
    		ans1/=Gcd,ans2/=Gcd;
    		
    		printf("%lld %lld
    ",ans1,ans2);
    	}
    }
    
  • 相关阅读:
    log记录日志使用说明
    浅谈WebService开发三(动态调用WebService)转
    浅谈WebService开发二(同步与异步调用)转
    浅谈WebService开发(一)转
    Log4net使用(二)
    Log4net使用(一)
    创建DSN
    Oracle的substr函数简单用法(转)
    医院里的CR、DR、CT、磁共振、B超都是什么?
    lambda表达式(2)
  • 原文地址:https://www.cnblogs.com/gmh77/p/12103683.html
Copyright © 2020-2023  润新知