您的位置:首页 > 产品设计 > UI/UE

【李超线段树】BZOJ1568[JSOI2008]Blue Mary开公司

2018-03-13 20:40 495 查看

前言:

这道题是李超线段树的一道模板题,鉴于李超线段树(似乎)应用性并不广,所以就用这道题顺便写写总结。

题目大意:

题目很鬼畜,一句话题意是:

动态插入一些离散的直线(有斜率),同时询问每条直线在某个点的取值的最大值。

算法介绍

差不多李超线段树就是干这个用的了

我们用一个标记来表示一个区间的最优线段,每次插入一个线段时,设原来的最优线段为l1l1,插入的线段为l2l2

首先比较两条线段的斜率大小,并且求出其分别在区间中点的值,

如果斜率较大的直线lmaxlmax在中点的取值比lminlmin小,那么lmaxlmax在左半部分一定被lminlmin或其他的线完全覆盖,所以只能向右区间转移。

如果lmaxlmax在中点的取值比lminlmin大,那么lminlmin在右半部分也一定被完全覆盖。只能向左区间转移。

最后求答案时,只需要将:线段树上覆盖了该节点的所有区间,分别求其最优线段在该点的取值,取最大值即可。

代码相当好写

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 50010
using namespace std;
double a[MAXN],b[MAXN],ans;
int n,q,tr[MAXN*4];
bool pushup(int x,int y,int now){
--now;
return a[x]+b[x]*now>a[y]+b[y]*now;
}
void update(int now,int l,int r,int id){
if(l==r){
if(pushup(now,tr[id],l))
tr[id]=now;
return;
}
int mid=(l+r)>>1;
if(b[now]>b[tr[id]]){
if(pushup(now,tr[id],mid)){
update(tr[id],l,mid,id*2);
tr[id]=now;
}
else
update(now,mid+1,r,id*2+1);
}
else{
if(pushup(now,tr[id],mid)){
update(tr[id],mid+1,r,id*2+1);
tr[id]=now;
}
else
update(now,l,mid,id*2);
}
}
void query(int q,int l,int r,int id){
ans=max(ans,a[tr[id]]+b[tr[id]]*(q-1));
if(l==r)
return ;
int mid=(l+r)>>1;
if(q<=mid)
query(q,l,mid,id*2);
else
query(q,mid+1,r,id*2+1);
}
char s[20];
int cnt,x;
int main(){
SF("%d",&q);
for(int i=1;i<=q;i++){
SF("%s",s);
if(s[0]=='P'){
cnt++;
SF("%lf%lf",&a[cnt],&b[cn
d805
t]);
update(cnt,1,MAXN-10,1);
}
else{
SF("%d",&x);
ans=0;
query(x,1,MAXN-10,1);
PF("%d\n",(int)ans/100);
}
}
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: