2019多校第九场 HDU6681 Rikka with Cake(欧拉图论定理,线段树)

链接HDU6681 Rikka with Cake

题意:

给出一个笛卡尔坐标系中左下角坐标为 ( 0 , 0 ) (0,0) ,右上角坐标为 ( n , m ) (n,m) 的矩形,有 K    ( 1 0 5 ) K\;(\le 10^5) 条射线,起点在矩形内部,其坐标为 ( x i , y i ) (x_i,y_i) ,方向为上/下/左/右( U / D / L / R ) U/D/L/R) ,且 i j ,    x i x j y i y j \forall i\neq j,\;x_i\neq x_j\land y_i\neq y_j 。( n , m , K , x i , y i N n,m,K,x_i,y_i\in N^*

问矩形一共被分成多少块?



分析:

欧拉图论定理:

如果一个 联通平面图 G G V V 个顶点、 E E 条边、 F F 个面,那么
V E + F = 2 V-E+F=2

①顶点个数 V V

  • 矩阵原顶点: 4 4
  • 矩阵边界与射线交点: K K
  • 射线起点: K K
  • 射线之间的交点: c c

V = 4 + 2 K + c V=4+2K+c


②边数 E E (即线段个数):

一条线段每多一个交点,就会被多分割出一条线段。

  • 矩形边界上线段个数: 4 + K 4+K
  • 射线上线段个数: K + 2 c K+2c (每个交点都同时存在于 2 2 条射线上)

E = 4 + 2 K + 2 c E=4+2K+2c


所以根据公式: V E + F = 2 V-E+F=2 ,可以得到平面内总分块数 F = c + 2 F=c+2 ,除去矩形外的无穷大区块,得到 a n s = c + 1 ans=c+1

于是问题就转化成了求射线的交点个数 c c ,离散化后用线段树/树状数组求解即可。



以下代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+50;
int n,m,K;
int X[maxn],Y[maxn];
struct ray
{
    int x,y;
    char dir;
}r[maxn];
bool cmp(const ray &a,const ray &b)
{
    return a.x<b.x;
}
void init()
{
    sort(X+1,X+K+1);
    sort(Y+1,Y+K+1);
    for(int i=1;i<=K;i++)
    {
        r[i].x=lower_bound(X+1,X+K+1,r[i].x)-X;
        r[i].y=lower_bound(Y+1,Y+K+1,r[i].y)-Y;
    }
}
int t[maxn<<2];
void updata(int rt,int l,int r,int val)
{
    if(l==r)
    {
        t[rt]++;
        return;
    }
    int mid=(l+r)>>1;
    if(val<=mid)
        updata(rt<<1,l,mid,val);
    else
        updata(rt<<1|1,mid+1,r,val);
    t[rt]=t[rt<<1]+t[rt<<1|1];
}
int query(int rt,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr)
        return t[rt];
    int res=0;
    int mid=(l+r)>>1;
    if(ql<=mid)
        res+=query(rt<<1,l,mid,ql,qr);
    if(qr>mid)
        res+=query(rt<<1|1,mid+1,r,ql,qr);
    return res;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d %d",&n,&m,&K);
        for(int i=1;i<=K;i++)
        {
            scanf("%d %d",&r[i].x,&r[i].y);
            getchar();
            r[i].dir=getchar();
            X[i]=r[i].x;
            Y[i]=r[i].y;
        }
        init();
        sort(r+1,r+K+1,cmp);
        int ans=0;
        memset(t,0,sizeof(t));
        for(int i=1;i<=K;i++)
        {
            int x=r[i].x,y=r[i].y;
            if(r[i].dir=='R')
                updata(1,1,K,y);
            else if(r[i].dir=='U')
                ans+=query(1,1,K,y,K);
            else if(r[i].dir=='D')
                ans+=query(1,1,K,1,y);
        }
        memset(t,0,sizeof(t));
        for(int i=K;i>=1;i--)
        {
            int x=r[i].x,y=r[i].y;
            if(r[i].dir=='L')
                updata(1,1,K,y);
            else if(r[i].dir=='U')
                ans+=query(1,1,K,y,K);
            else if(r[i].dir=='D')
                ans+=query(1,1,K,1,y);
        }
        printf("%d\n",ans+1);
    }
    return 0;
}
发布了214 篇原创文章 · 获赞 40 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Ratina/article/details/99843045
今日推荐