线段树维护一次函数

 

评测地址:https://www.codechef.com/problems/STREETTA

 

操作1:[l,r] 函数A对ax+b取大

操作2:[l,r] 函数B增加一次函数ax+b

操作3:询问 函数A在x位置的最大值+函数B在x位置的值,没有输出NA

r<=1e9

|a|,|b|<=1e9

操作数<=3e5

 

每次操作大约用log个节点,标记下传还要带log,所以线段树动态开节点

线段树标记永久化,询问从根一直走到它

函数增加直接加

函数取大:

1、原区间无函数,直接覆盖

2、无交点,用截距大的覆盖

3、交点在区间左端点,用斜率大的覆盖

4、交点在区间右端点,用斜率小的覆盖

5、交点在左子区间,下传截距大的,留下截距小的

6、交点在右子区间,下传截距小的,留下截距大的

(5、6 是在区间内部有交点,一定有一个函数只会影响一个子区间,下传这个函数)

 

下传函数时,

往左子区间传,斜率、截距都不改变

往右子区间传,斜率不变,截距改变

 

注意:代码中求函数交点,得到的是交点位置是将区间左端点看做0

 

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

#define N 300001

const double eps=1e-7;

struct node
{
    LL mxa,mxb;
    LL sma,smb;
    int lc,rc;
    bool HaveMx;
}tr[N*70];

int tot;

bool ok;

LL AnsMx,AnsSm;

void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    x*=f;
}

void query(int k,int l,int r,int pos)
{
    if(tr[k].HaveMx)
    {
        ok=true;
        AnsMx=max(AnsMx,(pos-l)*tr[k].mxa+tr[k].mxb);
    }
    AnsSm+=(pos-l)*tr[k].sma+tr[k].smb;
    if(l==r) return;
    int mid=l+r>>1;
    if(pos<=mid)
    {
        if(tr[k].lc) query(tr[k].lc,l,mid,pos);
    }
    else
    {
        if(tr[k].rc) query(tr[k].rc,mid+1,r,pos);
    }
}

void add(int &k,int l,int r,int opl,int opr,LL a,LL b)
{
    if(!k) k=++tot;
    if(l==opl && r==opr)
    {
        tr[k].sma+=a;
        tr[k].smb+=b;
        return;
    }
    int mid=l+r>>1;
    if(opr<=mid) add(tr[k].lc,l,mid,opl,opr,a,b);
    else if(opl>mid) add(tr[k].rc,mid+1,r,opl,opr,a,b);
    else
    {
        add(tr[k].lc,l,mid,opl,mid,a,b);
        add(tr[k].rc,mid+1,r,mid+1,opr,a,a*(mid+1-opl)+b);
    }
}

double getpoint(LL a1,LL b1,LL a2,LL b2)
{
    return 1.0*(b2-b1)/(a1-a2);
}

bool dcmp(double x,double y)
{
    return fabs(x-y)<eps;
}

void down(int &k,int l,int r,LL a,LL b)
{
    if(!k) k=++tot;
    if(l==r)
    {
        if(!tr[k].HaveMx)
        {
            tr[k].HaveMx=true;
            tr[k].mxa=a;
            tr[k].mxb=b;
        }
        else
        {
            if(b>tr[k].mxb)
            {
                tr[k].mxa=a;
                tr[k].mxb=b;
            }
        }
        return;
    }
    if(!tr[k].HaveMx)
    {
        tr[k].HaveMx=true;
        tr[k].mxa=a;
        tr[k].mxb=b;
    }
    else
    {
        if(a==tr[k].mxa)
        {
            if(b>tr[k].mxb) tr[k].mxb=b;
            return;
        }
        double foot=getpoint(a,b,tr[k].mxa,tr[k].mxb);
        if(foot<0 || foot>r-l+1)
        {
            if(b>tr[k].mxb)
            {
                tr[k].mxa=a;
                tr[k].mxb=b;
            }
        }
        else if(dcmp(foot,0))
        {
            if(a>tr[k].mxa)
            {
                tr[k].mxa=a;
                tr[k].mxb=b;
            }
        }
        else if(dcmp(foot,r-l+1))
        {
            if(a<tr[k].mxa)
            {
                tr[k].mxa=a;
                tr[k].mxb=b;
            }
        }
        else 
        {
            int mid=l+r>>1;
            if(l+foot<=mid)
            {
                if(b>tr[k].mxb) down(tr[k].lc,l,mid,a,b);
                else
                {
                    down(tr[k].lc,l,mid,tr[k].mxa,tr[k].mxb);
                    tr[k].mxa=a;
                    tr[k].mxb=b;
                }
            }
            else
            {
                if(b<tr[k].mxb) down(tr[k].rc,mid+1,r,a,a*(mid+1-l)+b);    
                else
                {
                    down(tr[k].rc,mid+1,r,tr[k].mxa,tr[k].mxa*(mid+1-l)+tr[k].mxb);
                    tr[k].mxa=a;
                    tr[k].mxb=b;
                }
            }
        }
    }
}

void getmax(int &k,int l,int r,int opl,int opr,LL a,LL b)
{
    if(!k) k=++tot;
    if(l==opl && r==opr)
    {
        down(k,l,r,a,b);
        return;
    }
    int mid=l+r>>1;
    if(opr<=mid) getmax(tr[k].lc,l,mid,opl,opr,a,b);
    else if(opl>mid) getmax(tr[k].rc,mid+1,r,opl,opr,a,b);
    else
    {
        getmax(tr[k].lc,l,mid,opl,mid,a,b);
        getmax(tr[k].rc,mid+1,r,mid+1,opr,a,a*(mid+1-opl)+b);
    }
}

int main()
{
    freopen("data.in","r",stdin);
    freopen("my.out","w",stdout);
    int n,m;
    read(n);
    read(m);
    int ty,l,r,a,b;
    int root=0;
    while(m--)
    {
        read(ty);
        if(ty==1)
        {
            read(l); read(r); read(a); read(b);
            getmax(root,1,n,l,r,a,b);
        }
        else if(ty==2)
        {
            read(l); read(r); read(a); read(b);
            add(root,1,n,l,r,a,b);
        }
        else
        {
            read(l);
            ok=false;
            AnsMx=-1LL<<62;
            AnsSm=0;
            query(root,1,n,l);
            if(!ok) puts("NA");
            else cout<<AnsMx+AnsSm<<'\n';
        }
    }
}

 

posted @ 2017-12-30 19:58  TRTTG  阅读(619)  评论(0编辑  收藏  举报