zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    70.BOM
    69.捕获错误try catch
    68.键盘事件
    523. Continuous Subarray Sum
    901. Online Stock Span
    547. Friend Circles
    162. Find Peak Element
    1008. Construct Binary Search Tree from Preorder Traversal
    889. Construct Binary Tree from Preorder and Postorder Traversal
    106. Construct Binary Tree from Inorder and Postorder Traversal
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9533241.html
Copyright © 2011-2022 走看看