[Educational Round 13][Codeforces 678F. Lena and Queries]

题目连接:678F - Lena and Queries

题目大意:要求对一个点集实现二维点对的插入,删除,以及询问\(q\):求\(max(x\cdot q+y)\)

题解:对每个点集内的点\(P(x_0,y_0)\),作过点\(P\)且斜率为\(-q\)的直线\(l\),则有\(l:y-y_0=-q(x-x_0)\),可以发现当\(x=0\)时,有\(y=q\cdot x_0+y_0\)。因此只要找到一个点,使得过此点作斜率为\(-q\)的直线在\(y\)轴上的截距最大即可。可以发现满足条件的点一定在一个上凸壳上,所以可以用三分来解决问题

   但由于需要处理点的插入和删除操作,直接在线求解比较麻烦,所以考虑离线处理询问

   因此我们只要记录每一个点的存在时间段,对时间建线段树,对线段树上的每一个节点暴力求出答案即可。由于每一个插入的点只会影响到\(log\  n\)个节点,所以总复杂度是\(O(nlog^2n)\)的

#include<bits/stdc++.h>
using namespace std;
#define N 300005
#define LL long long
struct Point
{
    LL x,y;
    Point operator -(const Point &t)const{return{x-t.x,y-t.y};}
    LL operator *(const Point &t)const{return x*t.y-y*t.x;}
    bool operator <(const Point &t)const{return x==t.x?y<t.y:x<t.x;}
}st[N];
LL n,cnt,o[N],q[N],f[N],c[N],r[N],x[N],y[N];
struct Segment_Tree
{
    struct rua
      {
      LL l,r;
      set<Point>s;
      }t[N<<2];
    void Build(LL l,LL r,LL x)
      {
      t[x].l=l,t[x].r=r;
      if(l==r)return;
      LL mid=l+r>>1;
      Build(l,mid,x*2);
      Build(mid+1,r,x*2+1);
      }
    void change(LL L,LL R,Point p,LL x)
      {
      LL l=t[x].l,r=t[x].r;
      LL mid=l+r>>1;
      if(L<=l && r<=R){t[x].s.insert(p);return;}
      if(L<=mid)change(L,R,p,x*2);
      if(mid<R)change(L,R,p,x*2+1);
      }
    void ask(LL x)
      {
      LL l=1,r=cnt;
      while(l+2<r)
        {
        LL mid1=(2*l+r)/3;
        LL mid2=(l+2*r)/3;
        if(q[x]*st[mid1].x+st[mid1].y<q[x]*st[mid2].x+st[mid2].y)l=mid1;
        else r=mid2;
        }
      for(LL i=l;i<=r;i++)f[x]=max(f[x],q[x]*st[i].x+st[i].y);
      }
    void get(LL x)
      {
      if(t[x].l<t[x].r)
        {
        get(x*2);
        get(x*2+1);
        }
      cnt=0;
      for(auto p:t[x].s)
        {
        while(cnt>1 && (st[cnt]-st[cnt-1])*(p-st[cnt])>=0)cnt--;
        st[++cnt]=p;
        }
      for(LL i=t[x].l;i<=t[x].r;i++)
        if(o[i]==3 && c[i])ask(i);
      }
}T;
int main()
{
    scanf("%I64d",&n);
    T.Build(1,n,1);
    for(LL i=1;i<=n;i++)
      {
      scanf("%I64d",&o[i]);
      if(o[i]==1)
        {
        scanf("%I64d%I64d",&x[i],&y[i]);
        r[i]=n,cnt++;
        }
      if(o[i]==2)
        {
        scanf("%I64d",&q[i]);
        r[q[i]]=i,cnt--;
        }
      if(o[i]==3)
        {
        scanf("%I64d",&q[i]),f[i]=-(5e18);
        }
      c[i]=cnt;
      }
    for(LL i=1;i<=n;i++)
      if(o[i]==1)T.change(i,r[i],{x[i],y[i]},1);
    T.get(1);
    for(LL i=1;i<=n;i++)
      if(o[i]==3)
        if(c[i])printf("%I64d\n",f[i]);
        else printf("EMPTY SET\n");
}
View Code

 

posted @ 2019-04-25 21:07  DeaphetS  阅读(366)  评论(0编辑  收藏  举报