Time:2016.08.02
Author:xiaoyimi
转载注明出处谢谢
传送门1
传送门2
思路:
题意大致为
维护有斜率和截距的若干直线,并求直线x=T(T∈N)与当前已加入直线交点的
ymax
利用李超线段树的优势区间维护[1,50000]的直线相交情况
新加入直线与线段树节点所存的原直线进行比较,取具有优势区间的直线作为线段树节点所存的新直线,另一直线在相应的区间内继续下放,最多下放
log(n)
次
查询时直接比较最大值即可,每次访问
log(n)
个节点
总时间复杂度
nlog(n)
(默认天数与询问次数同一数量级,均为n)
(以上均为个人见解,可能有不对的地方,望大神指正,共同进步)
注意:
好像不用标记??应该是有更优的做法吧,我的code码着码着就不像超哥线段树了
BZOJ跑了648ms
Tyvj在1s左右
代码:
#include<cstdio>
#include<iostream>
#define M 100004
#define inf 1e9
using namespace std;
int n;
char ch;
struct Seg
{
double k,b;
bool operator ==(const Seg other)const{
return k==other.k&&b==other.b;
}
}tr[M<<1];
Seg null={0,-inf};
double cal(int T,Seg x){return x.k*T+x.b;}
Seg judge(int T,Seg x,Seg y){return cal(T,x)>=cal(T,y)?x:y;}
void update(int rt,int begin,int end,Seg node)
{
Seg f1=judge(begin,tr[rt],node),
f2=judge(end,tr[rt],node);
if (f1==tr[rt]&&f2==tr[rt]) return;
else if (f1==node&&f2==node)
tr[rt]=node;
else
{
int mid=begin+end>>1;
double p=(node.b-tr[rt].b)/(tr[rt].k-node.k);
if (tr[rt].k>=node.k)
if (p<=mid)
update(rt<<1,begin,mid,node);
else
swap(node,tr[rt]),
update(rt<<1|1,mid+1,end,node);
else
if (p>mid)
update(rt<<1|1,mid+1,end,node);
else
swap(node,tr[rt]),
update(rt<<1,begin,mid,node);
}
}
Seg get(int rt,int begin,int end,int T)
{
if (begin==end) return tr[rt];
Seg p=tr[rt];
int mid=begin+end>>1;
if (mid>=T) return judge(T,p,get(rt<<1,begin,mid,T));
else return judge(T,p,get(rt<<1|1,mid+1,end,T));
}
main()
{
scanf("%d",&n);
while (n--)
{
ch=getchar();
while (ch!='P'&&ch!='Q') ch=getchar();
while (getchar()!=' ');
if (ch=='P')
{
double k,b;
scanf("%lf%lf",&b,&k);
update(1,0,50000-1,(Seg){k,b});
}
else
{
int p;
scanf("%d",&p);
p--;
Seg ans=get(1,0,50000-1,p);
printf("%d\n",(int)(cal(p,ans)/100));
}
}
}