• BZOJ1568: [JSOI2008]Blue Mary开公司


    BZOJ1568: [JSOI2008]Blue Mary开公司

    Description

    Input

    第一行 :一个整数N ,表示方案和询问的总数。 
    接下来N行,每行开头一个单词“Query”或“Project”。 
    若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益。 
    若单词为Project,则后接两个实数S,P,表示该种设计方案第一天的收益S,以及以后每天比上一天多出的收益P。
    1 <= N <= 100000 1 <= T <=50000 0 < P < 100,| S | <= 10^6 
    提示:本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。

    Output

    对于每一个Query,输出一个整数,表示询问的答案,并精确到整百元(以百元为单位,
    例如:该天最大收益为210或290时,均应该输出2)。没有方案时回答询问要输出0

    Sample Input

    10
    Project 5.10200 0.65000
    Project 2.76200 1.43000
    Query 4
    Query 2
    Project 3.80200 1.17000
    Query 2
    Query 3
    Query 1
    Project 4.58200 0.91000
    Project 5.36200 0.39000

    Sample Output

    0
    0
    0
    0
    0

    题解Here!
    其实这个算是裸题了。。。
    题目要求区间内的所有直线的最高点的最大值。
    这种问题丢给李超树就好。。。
    然后学会李超树的可以去看这题:BZOJ4515: [Sdoi2016]游戏
    套上一个树剖就解决了。

    步入正题:

    李超树,俗称超哥线段树,是国家队队爷李超发明出来专门解决这一类问题:

    现有2种操作:

    1. 在平面上插入一条直线$y=kx+b$

    2. 求在$[l,r]$范围内直线上的点的纵坐标的最大值

    对付这种问题,超哥线段树是这么解决的:

    假设在$[l,r]$内原有的一条直线为$f(x)_ 1=k_1x+b_1$

    在这个区间内加入的直线为$f(x)_ 2=k_2x+b_2$

    1. 如果$f(l)_ 2>=f(l)_ 1,f(r)_ 2>=f(r)_ 1$,那么说明$f(x)_ 1$在这个区间内被$f(x)_ 2$吊打,那么直接替换即可。
    2. 如果$f(l)_ 2<=f(l)_ 1,f(r)_ 2<=f(r)_ 1$,那么说明$f(x)_ 2$在这个区间内被$f(x)_ 1$吊打,那么不做任何操作。
    3. 如果$f(l)_ 2<=f(l)_ 1,f(r)_ 2>=f(r)_ 1$或者$f(l)_ 2>=f(l)_ 1,f(r)_ 2<=f(r)_ 1$,说明两直线在这个区间内有交点,则取区间中点$mid$,判断两直线在区间$[l,mid]$中是否相交:是,则右区间$[mid+1,r]$改为在上方的直线,左区间递归求解;否,则左区间$[l,mid]$改为在上方的直线,右区间递归求解。

    而递归求解最多涉及到$log_2n$个节点。

    所以这样的复杂度上限是$O(log_2^2n)$。

    然后,这题还需要用到标记永久化。

    即我们不下传标记,在求区间最大值的时候,每次访问到一个和询问区间有交集的区间,把答案和这个区间所维护的线段取$min$。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define LSON rt<<1
    #define RSON rt<<1|1
    #define DATA(x) a[x].data
    #define MUL(x) a[x].k
    #define ADD(x) a[x].v
    #define SIGN(x) a[x].c
    #define LSIDE(x) a[x].l
    #define RSIDE(x) a[x].r
    #define MAXN 100010
    using namespace std;
    int n,m;
    struct Segment_Tree{
    	double data,k,v;
    	bool c;
    	int l,r;
    }a[MAXN<<2];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline void pushup(int rt){
    	DATA(rt)=max(DATA(rt),max(DATA(LSON),DATA(RSON)));
    }
    void buildtree(int l,int r,int rt){
    	LSIDE(rt)=l;RSIDE(rt)=r;
    	DATA(rt)=0;SIGN(rt)=false;
    	if(l==r)return;
    	int mid=l+r>>1;
    	buildtree(l,mid,LSON);
    	buildtree(mid+1,r,RSON);
    }
    void change(double k,double v,int rt){
    	if(!SIGN(rt)){
    		SIGN(rt)=true;
    		MUL(rt)=k;ADD(rt)=v;
    		DATA(rt)=max(DATA(rt),max(k*LSIDE(rt),k*RSIDE(rt))+v);
    		return;
    	}
    	double l1=MUL(rt)*LSIDE(rt)+ADD(rt),l2=k*LSIDE(rt)+v;
    	double r1=MUL(rt)*RSIDE(rt)+ADD(rt),r2=k*RSIDE(rt)+v;
    	if(l2<=l1&&r2<=r1)return;
    	else if(l2>l1&&r2>r1){
    		MUL(rt)=k;ADD(rt)=v;
    		DATA(rt)=max(DATA(rt),max(k*LSIDE(rt),k*RSIDE(rt))+v);
    		return;
    	}
    	int mid=LSIDE(rt)+RSIDE(rt)>>1;
    	double mid1=MUL(rt)*mid+ADD(rt),mid2=k*mid+v;
    	if(l2<=l1){
    		if(mid2<=mid1)change(k,v,RSON);
    		else{
    			change(MUL(rt),ADD(rt),LSON);
    			MUL(rt)=k;ADD(rt)=v;
    			DATA(rt)=max(DATA(rt),max(k*LSIDE(rt),k*RSIDE(rt))+v);
    		}
    	}
    	else{
    		if(mid2<=mid1)change(k,v,LSON);
    		else{
    			change(MUL(rt),ADD(rt),RSON);
    			MUL(rt)=k;ADD(rt)=v;
    			DATA(rt)=max(DATA(rt),max(k*LSIDE(rt),k*RSIDE(rt))+v);
    		}
    	}
    	pushup(rt);
    }
    void update(int l,int r,double k,double v,int rt){
    	if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
    		change(k,v,rt);
    		return;
    	}
    	int mid=LSIDE(rt)+RSIDE(rt)>>1;
    	if(l<=mid)update(l,r,k,v,LSON);
    	if(mid<r)update(l,r,k,v,RSON);
    	pushup(rt);
    }
    double query(int l,int r,int rt){
    	double ans=0;
    	if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
    	int mid=LSIDE(rt)+RSIDE(rt)>>1;
    	if(l<=mid)ans=max(ans,query(l,r,LSON));
    	if(mid<r)ans=max(ans,query(l,r,RSON));
    	if(SIGN(rt))ans=max(ans,max(MUL(rt)*max(l,LSIDE(rt)),MUL(rt)*min(r,RSIDE(rt)))+ADD(rt));
    	return ans;
    }
    void work(){
    	char ch[15];
    	while(m--){
    		scanf("%s",ch);
    		if(ch[0]=='P'){
    			double x,y;
    			scanf("%lf%lf",&x,&y);
    			update(1,n,y,x-y,1);
    		}
    		else{
    			int x=read();
    			printf("%d
    ",(int)query(x,x,1)/100);
    		}
    	}
    }
    void init(){
    	m=read();n=MAXN-10;
    	buildtree(1,n,1);
    }
    int main(){
    	init();
    	work();
        return 0;
    }
    
  • 相关阅读:
    关于meta便签详解
    移动端等分比显示导航状态
    css3单选 复选按钮--代码分享
    css-样式重构-代码分享
    代码分享h5-sessionStorage,提示app下载代码块
    微信浏览器打开 点击下载app 无需提示使用浏览器打开--代码分享
    js 判断IOS版本号
    二进制,八进制,十进制,十六进制之间的转换
    JS组件系列——Bootstrap文件上传组件:bootstrap fileinput
    Bootstrap文件上传插件File Input的使用
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9533241.html
Copyright © 2020-2023  润新知