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\n",ans1,ans2);
    }
}

猜你喜欢

转载自www.cnblogs.com/gmh77/p/12103683.html