zoukankan      html  css  js  c++  java
  • HDU6681 Rikka with Cake

    题意

    给一个n*m的矩形,n,m 1e9。给k(1e5)个点坐标(x,y),每个点可向上下左右发出射线,问将矩形分成几份。
    题目连接

    思路

    观察发现分成的块数等于交点数加一。离散化上下分别考虑,对于下垂下来的线按照下垂点从下向上插入树状数组,同时从下向上查询水平射线,对于向左的射线,查询小于等于其发出点x坐标的下垂线有几个,对于向右的射线,查询大于等于其发出点x坐标的下垂线有几个。对于向上的线同理。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn = 100000+10;
    
    struct line
    {
        int x,y,o;
    };
    
    struct node
    {
        int p,v;
    };
    
    int n,m,k,nn,mm;
    char s[10];
    line a[maxn];
    int b[maxn],c[maxn],u[maxn],d[maxn],l[maxn],r[maxn];
    node tmp[maxn];
    int t[maxn];
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void add(int x)
    {
        while (x<=nn)
        {
            t[x]++;
            x+=lowbit(x);
        }
    }
    
    int ask(int x)
    {
        int ans=0;
        while (x>0)
        {
            ans+=t[x];
            x-=lowbit(x);
        }
        return ans;
    }
    
    bool cmp(node a,node b)
    {
        return a.v<b.v;
    }
    
    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",&a[i].x,&a[i].y);
                scanf("%s",s);
                if (s[0]=='U') a[i].o=1; else
                if (s[0]=='D') a[i].o=2; else
                if (s[0]=='L') a[i].o=3; else
                if (s[0]=='R') a[i].o=4;
                b[i]=a[i].x;
                c[i]=a[i].y;
            }
            nn=k;
            b[++nn]=0; b[++nn]=n;
            mm=k;
            c[++mm]=0; c[++mm]=m;
            sort(b+1,b+nn+1);
            sort(c+1,c+mm+1);
            nn=unique(b+1,b+nn+1)-b-1;
            mm=unique(c+1,c+mm+1)-c-1;
            for (int i=1;i<=k;i++)
            {
                a[i].x=lower_bound(b+1,b+nn+1,a[i].x)-b;
                a[i].y=lower_bound(c+1,c+mm+1,a[i].y)-c;
            }
            for (int i=1;i<=nn;i++) u[i]=mm,d[i]=1;
            for (int i=1;i<=mm;i++) l[i]=1,r[i]=nn;
            for (int i=1;i<=k;i++)
            {
                if (a[i].o==1) u[a[i].x]=min(u[a[i].x],a[i].y); else
                if (a[i].o==2) d[a[i].x]=max(d[a[i].x],a[i].y); else
                if (a[i].o==3) l[a[i].y]=max(l[a[i].y],a[i].x); else
                if (a[i].o==4) r[a[i].y]=min(r[a[i].y],a[i].x);
            }
            for (int i=1;i<=nn;i++)
            {
                if (u[i]<=d[i]) u[i]=1,d[i]=1;
            }
            for (int i=1;i<=mm;i++)
            {
                if (l[i]>=r[i]) l[i]=nn,r[i]=nn;
            }
    
            LL ans=1;
    
            for (int i=1;i<=nn;i++) tmp[i].p=i,tmp[i].v=u[i];
            sort(tmp+1,tmp+nn+1,cmp);
            int cur=1;
            memset(t,0,sizeof(t));
            for (int i=1;i<mm;i++)
            {
                while (cur<=nn&&tmp[cur].v<=i)
                {
                    add(tmp[cur].p);
                    cur++;
                }
                ans+=ask(l[i]);
                ans+=ask(nn)-ask(r[i]-1);
            }
    
            for (int i=1;i<=nn;i++) tmp[i].p=i,tmp[i].v=d[i];
            sort(tmp+1,tmp+nn+1,cmp);
            cur=nn;
            memset(t,0,sizeof(t));
            for (int i=mm;i>1;i--)
            {
                while (cur>=1&&tmp[cur].v>=i)
                {
                    add(tmp[cur].p);
                    cur--;
                }
                ans+=ask(l[i]);
                ans+=ask(nn)-ask(r[i]-1);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    删除XML文档中某节点
    水晶报表之创建子报表
    给字符串中的每个字符加上单引号
    Failed to export using the options you specified. Please check your options and try again
    从ASP.NET传递参数给水晶报表
    两个文本框异动任何一个能即时更新计算结果
    添加节点至XML文档中去
    读取XML文档存入泛型List<T>集合中
    泛型List<T>转存为XML文档
    怎样创建XML文档
  • 原文地址:https://www.cnblogs.com/zhanggengchen/p/11381818.html
Copyright © 2011-2022 走看看