zoukankan      html  css  js  c++  java
  • 【BZOJ1568】[JSOI2008] Blue Mary开公司(卡精度线段树)

    点此看题面

    大致题意: 两种操作:新给你一条斜率大于(0)的直线;给定横坐标(整数),问已知直线中最大的(y)值。

    卡精度

    绝望的卡精度。。。

    可能是我的做法和别人不太一样,看了下题解似乎都是李超线段树(不知道这是什么神仙东西),甚至还有一个暴力水过的,好像就我一个人写线段树上二分 emmm

    在BZOJ上卡精度卡了一个晚上都没能过,第二天到机房接着卡,又花了一个半小时才过了。

    结果到洛谷上又(WA)了,只有(70)分,但实在是不想调,只好扔在那里,假装我过了。

    当然,或许并不是精度炸了,而是写挂了,如果真是这样,希望能帮我指出。

    线段树上二分

    考虑每条直线的答案区间,最后发现必然长成这个样子:

    每条直线斜率递增,且必然对应一段区间的答案

    然后考虑新加入一条直线,如果对答案有贡献,就应该是这个样子的:

    对于这种情况,可以发现必然是超过一条斜率较小的直线,最终又被斜率较大的直线超越。

    所以我们就可以线段树上二分出它能作为答案的左右区间。

    应该是挺好理解的。

    至于二分的细节可以详见代码注释。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define DB long double
    using namespace std;
    int n;DB k[N+5],b[N+5];
    class SegmenTree
    {
    	private:
    		#define PT CI l=0,CI r=n-1,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1
    		#define PU(x) (O[x].L=O[x<<1].L,O[x].R=O[x<<1|1].R)
    		#define PD(x) O[x].id&&(T(x<<1,O[x].id),T(x<<1|1,O[x].id),O[x].id=0)
    		#define T(x,p) (O[x].id=O[x].L=O[x].R=p)
    		#define f(p,x) (k[p]*(x)+b[p])
    		struct node {int id,L,R;}O[N<<2];
    		I int FL(CI p,PT)//找左端点
    		{
    			if(f(O[rt].L,l)<=f(p,l)&&f(O[rt].R,r)<=f(p,r)) return l;
    			//如果左端点和右端点的值都较小,说明肯定这整段区间都被新直线碾压,直接返回左端点
    			if(l==r||(f(O[rt].L,l)>f(p,l)&&k[O[rt].L]>=k[p])) return -1;
    			//如果到了单点,或者左端点的值比新直线大,且斜率更大,说明新直线永远无法超越原答案,返回-1
    			RI mid=l+r>>1;PD(rt);if(k[O[rt<<1|1].L]>k[p]) return FL(p,LT);
    			//因为要保证斜率递减,所以若右区间斜率不满足限制就去搞左区间
    			return f(O[rt<<1].R,mid)<=f(p,mid)?FL(p,LT):FL(p,RT);
    			//尽可能走左区间
    		}
    		I int FR(CI p,PT)//找右端点,和上面大致一样,不再重复
    		{
    			if(f(O[rt].L,l)<=f(p,l)&&f(O[rt].R,r)<=f(p,r)) return r;
    			if(l==r||(f(O[rt].L,l)>f(p,l)&&k[O[rt].L]>=k[p])) return -1;
    			RI mid=l+r>>1;PD(rt);if(k[O[rt<<1].R]<k[p]) return FR(p,RT);
    			return f(O[rt<<1|1].L,mid+1)<=f(p,mid+1)?FR(p,RT):FR(p,LT);
    		}
    		I void U(CI x,CI y,CI p,PT)//区间修改为新直线
    		{
    			if(x<=l&&r<=y) return (void)T(rt,p);RI mid=l+r>>1;PD(rt);
    			x<=mid&&(U(x,y,p,LT),0),y>mid&&(U(x,y,p,RT),0),PU(rt);
    		}
    	public:
    		I void U(CI p)//修改
    		{
    			RI l=k[O[1].L]<=k[p]?FL(p):0,r=k[O[1].R]>=k[p]?FR(p):n-1;//注意没有斜率更小/斜率更大的直线的边界
    			~l&&~r&&l<=r&&(U(l,r,p),0);
    		}
    		I int Q(CI x,PT)//询问
    		{
    			if(l==r||O[rt].id) return O[rt].id;
    			RI mid=l+r>>1;return x<=mid?Q(x,LT):Q(x,RT);
    		}
    }S;
    int main()
    {
    	char s[10];DB x,y;for(RI i=(scanf("%d",&n),1),t=0,p,q;i<=n;++i)
    	{
    		if(scanf("%s",s),s[0]=='P') ++t,scanf("%Lf%Lf",&b[t],&k[t]),S.U(t);//修改
    		else scanf("%d",&q),p=S.Q(q-1),printf("%d
    ",(int)floor((k[p]*(q-1)+b[p])/100));//询问
    	}return 0;
    }
    
  • 相关阅读:
    VS2010 使用TeeChart画图控件
    程序猿接私活经验总结,来自csdn论坛语录
    锁(下)
    android4.4组件分析--service组件-bindService源代码分析
    黑客和敏捷开发
    编写你自己的单点登录(SSO)服务
    Cloudera impala简单介绍及安装具体解释
    ACdream群赛1112(Alice and Bob)
    八大排序算法总结
    垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1568.html
Copyright © 2011-2022 走看看