zoukankan      html  css  js  c++  java
  • [Codeforces]856E Satellites

      二维询问转化成一维询问的问题,话说CF上面的好题还真多。

    Description

      给定一个半径为r的半圆,圆心为坐标原点O,直径为AB,半圆弧位于x轴上方。给定n次操作,每次为以下3种操作之一:

        ①1 x y — 在(x,y)处放置一颗卫星,如果该卫星是第 i 个被放到平面上的卫星,则它的编号为i;

        ②2 i — 移除编号为 i 的卫星;

        ③3 i j — 对卫星 i 和卫星 j 进行询问,若在卫星 i 和卫星 j 的公共控制区域能够找到一个点,满足这个点不被其他卫星所控制,那么输出"YES",否则输出"NO"。

      一颗卫星点P的控制区域为△PAB中的不在⊙O内的部分。如下图绿色区域:

        

    Input

      第一行两个整数r,n。

      接下来n行,每行表示一个操作。

    Output

      对于每个操作3,输出"YES"或“NO”。

    Sample Input

      5 8
      1 -5 8
      1 -4 8
      1 -3 8
      1 2 7
      3 1 3
      2 2
      3 1 3
      3 3 4

    Sample Output

      NO
      YES
      YES

    HINT

      1<=r<=10^9,1<=n<=5*10^5。

      |x|<=10^9,0<y<=10^9,且(x,y)保证在圆外。

      对于操作2、3中的i、j,满足在执行此操作之前,卫星 i 和卫星 j 一定在平面上。

    Solution

      又是这样一道带操作的题,在开始打数据结构之前,我们分析一下题意:

      操作1和操作2分别是插入和删除操作,而操作3是在询问两个二维平面的交 内是否有不被其他区间覆盖的点。

      很显然就是叫我们求如下图的绿色区域内是否有其他卫星。

        

      那么绿色区域内的卫星P满足什么条件呢?用k(α)表示直线α与x轴正方向的夹角,那么有:

        k(AP)>k(AP2)且k(BP)<k(BP1)。

      这么一来,做法一下子就变得显而易见了。

      对于每个点Pi,把k(BPi)看作第一维,把k(APi)看作第二维,维护第二维出现的次数,目的是求和,判定条件是 和是否大于0。

      然而数据范围是50W,如果你头戴金刚钻是可以用cdq分治O(nlog2n)通过该题的。

      我们继续分析这道题的性质:我们发现两维的询问都是在询问整段序列的一半,而且判定条件是和大于1即可。

      所以我们只要对于每个第一维,维护第二维的最大值,这样就变成了求矩形最大值,判定条件是 求得的最大值是否超过限制(你懂的)。

      而且这个矩形最大值实际上只跟第一维有关系,询问的是第二维的全部,所以我们用线段树套堆就可以将复杂度降为O(nlogn)。

      具体做法什么的只要脑补一下就行了。

      最需要注意的是这题可能会带来精度上的困扰,所以各种计算和判定尽量使用向量来进行。

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #define ll long long
    #define l(a) (a<<1)
    #define r(a) (a<<1|1)
    #define MN 500005
    #define MD 1100005
    using namespace std;
    struct vec
    {
        int x,y;
        friend ll operator/(const vec& a,const vec& b) {return 1LL*a.x*b.y-1LL*a.y*b.x;}
        friend ll operator*(const vec& a,const vec& b) {return 1LL*a.x*b.x+1LL*a.y*b.y;}
    };
    struct meg{int g,x,y;}a[MN];
    struct met{vec v;int pos;}b0[MN],b1[MN];
    struct its{int x,y;}s[MN];
    struct itv{vec x,y;}d[MN];
    struct Que
    {
        priority_queue <int> A,B;
        void push(int x) {A.push(x);}
        void dele(int x) {B.push(x);}
        int top()
        {
            while (!B.empty()&&A.top()==B.top()) A.pop(),B.pop();
            if (!A.empty()) return A.top(); else return 0;
        }
    }q[MN];
    int m,MQ,tin,b0in,b1in,ra;
    int t[MD];
    
    inline int read()
    {
        int n=0,f=1; char c=getchar();
        while (c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
        while (c>='0' && c<='9') {n=n*10+c-'0'; c=getchar();}
        return n*f;
    }
    
    inline void getcg(int x,int z) {for (t[x+=MQ]=z,x>>=1;x;x>>=1) t[x]=max(t[l(x)],t[r(x)]);}
    inline int getmax(int L,int R)
    {
        int sum=0;
        for (L+=MQ,R+=MQ;L<=R;L>>=1,R>>=1)
        {
            if ( L&1) sum=max(sum,t[L++]);
            if (~R&1) sum=max(sum,t[R--]);
        }
        return sum;
    }
    
    void cghp(int x,int y,int g)
    {
        int lt=q[x].top();
        if (g==1) q[x].push(y); else q[x].dele(y);
        if (lt!=q[x].top()) getcg(x,q[x].top());
    }
    
    bool check(int x,int y)
    {
        int cs1,cs2;
        if (s[x].x>s[y].x) cs1=x; else cs1=y;
        if (s[x].y<s[y].y) cs2=x; else cs2=y;
        if (d[cs2].y*d[cs1].x<0) return true; else return false;
    }
    
    bool cmp(const met& a,const met& b) {return a.v/b.v>0;}
    
    int main()
    {
        register int i,x,y;
        ra=read(); m=read();
        for (i=1;i<=m;++i)
        {
            a[i].g=read();
            if (a[i].g==1)
            {
                x=read(); y=read(); a[i].x=++tin;
                d[tin].x.x=x-ra; d[tin].x.y=y;
                d[tin].y.x=x+ra; d[tin].y.y=y;
                b0[++b0in]=(met){d[tin].x,tin};
                b1[++b1in]=(met){d[tin].y,tin};
            }
            else if (a[i].g==2) a[i].x=read();
            else if (a[i].g==3) a[i].x=read(),a[i].y=read();
        }
        sort(b0+1,b0+b0in+1,cmp); sort(b1+1,b1+b1in+1,cmp);
        b0[0].pos=b1[0].pos=s[0].x=s[0].y=0;
        for (i=1;i<=b0in;++i)
            if (i>1&&b0[i-1].v/b0[i].v==0) s[b0[i].pos].x=s[b0[i-1].pos].x;
            else s[b0[i].pos].x=s[b0[i-1].pos].x+1;
        for (i=1;i<=b1in;++i)
            if (i>1&&b1[i-1].v/b1[i].v==0) s[b1[i].pos].y=s[b1[i-1].pos].y;
            else s[b1[i].pos].y=s[b1[i-1].pos].y+1;
        b0in=s[b0[b0in].pos].x;
        for (MQ=1;MQ<b0in;MQ<<=1); --MQ;
        for (i=1;i<=m;++i)
        {
            if (a[i].g<3) cghp(s[a[i].x].x,s[a[i].x].y,a[i].g);
            else if (a[i].g==3)
            {
                if (check(a[i].x,a[i].y)) {puts("NO"); continue;}
                x=max(s[a[i].x].x,s[a[i].y].x); y=min(s[a[i].x].y,s[a[i].y].y);
                cghp(s[a[i].x].x,s[a[i].x].y,2);
                cghp(s[a[i].y].x,s[a[i].y].y,2);
                if (getmax(1,x)>=y) puts("NO"); else puts("YES");
                cghp(s[a[i].x].x,s[a[i].x].y,1);
                cghp(s[a[i].y].x,s[a[i].y].y,1);
            }
        }
    }

    Last Word

      又一次感受到了精度在某些题使人发狂程度的能力。

      然后就不得不感叹一句向量真是好用。

  • 相关阅读:
    Mockito 简明教程
    说说初用 Mock 工具测试碰到的坑
    java的mock测试框架
    使用模拟对象(Mock Object)技术进行测试驱动开发
    微信小程序
    微信小程序
    uniapp
    微信小程序
    微信小程序
    微信小程序
  • 原文地址:https://www.cnblogs.com/ACMLCZH/p/7526216.html
Copyright © 2011-2022 走看看