zoukankan      html  css  js  c++  java
  • BZOJ1568: [JSOI2008]Blue Mary开公司

    可以平衡树或线段树维护斜率来做。还有一种线段树直接打标记的做法(李超线段树):线段树每个节点存一条线段作为标记,打标记时如果已有标记,则把占优区间小的那个线段下放。

    #include<cstdio>
    #include<algorithm>
    #define N 50000
    #define M (l+r>>1)
    #define P (k<<1)
    #define S (k<<1|1)
    #define L l,M,P
    #define R M+1,r,S
    #define Z 
    int l=0,int r=N-1,int k=1
    using namespace std;
    struct node{
    	double s,t;
    	double val(int x){
    		return s*x+t;
    	}
    }e[N*2],*u=e,*a[N*4];
    void apply(node*s,Z){
    	if(!a[k])a[k]=s;
    	else{
    		if(a[k]->val(M)<s->val(M))
    			swap(a[k],s);
    		if(l!=r)
    			a[k]->s<s->s?apply(s,R):apply(s,L);
    	}
    }
    double query(int s,Z){
    	double v=a[k]?a[k]->val(s):0;
    	if(l!=r)
    		v=max(v,s<=M?query(s,L):query(s,R));
    	return v;
    }
    int i,m;
    char k[8];
    double s,t;
    int main(){
    	for(scanf("%d",&m);m;--m){
    		scanf("%s",k);
    		if(*k==80){
    			scanf("%lf%lf",&t,&s);
    			apply(&(*u++=(node){s,t}));
    		}
    		else{
    			scanf("%d",&i);
    			printf("%d
    ",(int)query(i-1)/100);
    		}
    	}
    }
    

    之前写的是一个奇怪的做法……

    答案序列一定是个下凸壳,因此添加的等差数列与其之差是个单峰函数,可以先三分求出最值,再二分求出零点,然后用线段树,将得到的区间修改为一个等差数列。

    要降低复杂度的话可以把三分和二分写到线段树里面……

    #include<cstdio>
    #define Z 
    int l=1,int r=N,int k=1
    #define N 50000
    #define M (l+r>>1)
    #define P (k<<1)
    #define S (k<<1|1)
    #define K l,r,k
    #define L l,M,P
    #define R M+1,r,S
    double a[N*4],b[N*4];
    void devolve(Z){
    	if(b[k]){
    		a[S]=a[k]+(M-l+1)*(b[P]=b[S]=b[k]);
    		a[P]=a[k],b[k]=0;
    	}
    }
    double query(int s,Z){
    	if(l!=r){
    		devolve(K);
    		return s<=M?query(s,L):query(s,R);
    	}
    	return a[k];
    }
    void amend(double u,double v,int s,int t,Z){
    	if(s==l&&t==r)
    		a[k]=u,b[k]=v;
    	else{
    		devolve(K);
    		if(t<=M)
    			amend(u,v,s,t,L);
    		else if(s>M)
    			amend(u,v,s,t,R);
    		else{
    			amend(u,v,s,M,L);
    			amend(u+(M-s+1)*v,v,M+1,t,R);
    		}
    	}
    }
    double s,t;
    int i,j,m,r,l;
    char k[8];
    void solve(){
    	scanf("%lf%lf",&s,&t);
    	l=1,r=N;
    	while(l!=r){
    		i=l+(r-l)/3;
    		j=r-(r-l)/3;
    		if(t*(i-j)<query(i)-query(j))
    			l=i+1;
    		else r=j-1;
    	}
    	if(s+t*l-t>query(l)){
    		r=l,l=1;
    		while(l!=r){
    			i=l+r>>1;
    			if(s+t*i-t>query(i))
    				r=i;
    			else l=i+1;
    		}
    		j=l,r=N;
    		while(l!=r){
    			i=l+r+1>>1;
    			if(s+t*i-t>query(i))
    				l=i;
    			else r=i-1;
    		}
    		amend(s+t*j-t,t,j,l);
    	}
    }
    int main(){
    	for(scanf("%d",&m);m;--m){
    		scanf("%s",k);
    		if(*k==80)
    			solve();
    		else{
    			scanf("%d",&i);
    			printf("%d
    ",(int)query(i)/100);
    		}
    	}
    }
    

    最后吐槽一句这题啥破样例啊。

  • 相关阅读:
    电路学习实战分析之mos-2
    我这博客咋分类的?
    学习shell之后,实战分析
    二叉树,二叉排序树,红黑树 学习
    哈希表 学习
    《转》C语言可变参函数的实现
    Linux工具记录
    苏州之旅有感
    git 命令动画学
    软件工程相关博客
  • 原文地址:https://www.cnblogs.com/f321dd/p/5745212.html
Copyright © 2011-2022 走看看