bzoj1568

李超线段树

李超线段树的每个节点维护一个区间,并且用标记记录当前区间上的最优线段的标号

对于add一条新的线段:

1.该区间无标记,则打上这条线段的标号

2.若新线段在该区间上的左右端点的y值都>=原标记线段在该区间上的左右端点的y值,则新线段更优,直接覆盖

3.若新线段在该区间上的左右端点的y值都<=原标记线段在该区间上的左右端点的y值,则原线段更优,直接return

4.若不满足上述三种情况,则两线段必有交点

  新直线的mid处的值>=原直线&&新直线l处值>=原直线,则将原线段递归到右儿子上去贡献,新线段标号作为这段区间的标记

  新直线的mid处的值>=原直线&&新直线l处值<=原直线,则将原线段递归到左儿子上去贡献,新线段标号作为这段区间的标记

  新直线的mid处的值<=原直线&&新直线l处值>=原直线,则将新线段递归到左儿子上去贡献,这段区间的标记不变

  新直线的mid处的值<=原直线&&新直线l处值<=原直线,则将新线段递归到右儿子上去贡献,这段区间的标记不变

最后询问的时候一路带上标记即可(标记永久化)

/**************************************************************

    Problem: 1568

    User: syh0313

    Language: C++

    Result: Accepted

    Time:560 ms

    Memory:7544 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <string>

#include <cmath>

#include <algorithm>

#define lch a[n].lc

#define rch a[n].rc

using namespace std;

const int maxn=100010;

const double eps=1e-8;

double b[maxn],k[maxn],ans;

int n,t,root,topt,xx,now;

struct da{int lc,rc,id;}a[4*maxn];

char s[20];

void build_tree(int &n,int l,int r)

{

    n=++topt; a[n].id=0;

    if (l==r) return;

    int mid=(l+r)>>1;

    build_tree(lch,l,mid); build_tree(rch,mid+1,r);

}

double yz(double x,int kk) {return x*k[kk]+b[kk];}

void tree_add(int n,int L,int R,int l,int r,int k)

{

    int mid=(L+R)>>1;

    if (L==l && R==r)

    {

        if (!a[n].id) {a[n].id=k; return;}

        if (yz(l,k)>=yz(l,a[n].id) && yz(r,k)>=yz(r,a[n].id)) {a[n].id=k; return;}

        if (yz(l,k)<=yz(l,a[n].id) && yz(r,k)<=yz(r,a[n].id)) return;

        if (yz((double)(l+r)/2.0,a[n].id)<=yz((double)(l+r)/2.0,k))

        {

            if (yz(l,k)>=yz(l,a[n].id)) tree_add(rch,mid+1,R,mid+1,r,a[n].id);

            else tree_add(lch,L,mid,l,mid,a[n].id);

            a[n].id=k;

        }

        else

        {

            if (yz(l,k)>=yz(l,a[n].id)) tree_add(lch,L,mid,l,mid,k);

            else tree_add(rch,mid+1,R,mid+1,r,k);

        }

        return;

    }

    if (r<=mid) tree_add(lch,L,mid,l,r,k);

    else if (l>=mid+1) tree_add(rch,mid+1,R,l,r,k);

    else tree_add(lch,L,mid,l,mid,k),tree_add(rch,mid+1,R,mid+1,r,k);

}

void qury(int n,int l,int r,int lc)

{

    if (a[n].id) ans=max(ans,k[a[n].id]*lc+b[a[n].id]);

    if (l==r) return;

    int mid=(l+r)>>1;

    if (lc<=mid) qury(lch,l,mid,lc);else qury(rch,mid+1,r,lc);

}

int main()

{

    scanf("%d",&n); t=50000; build_tree(root,1,t);

    for (int i=1;i<=n;i++)

    {

        scanf("%s",s+1);

        if (s[1]=='P')

        {

            scanf("%lf%lf",&b[i],&k[i]); b[i]-=k[i];

            tree_add(root,1,t,1,t,i);

        }

        else

        {

            scanf("%d",&xx); ans=0; qury(root,1,t,xx);

            printf("%lld\n",(long long)ans/100ll);

        }

    }

return 0;

}



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值