题解 P5554 【篮球统计】
出题人: hsfzLZH1
本题主要考察模型转化和线段树。
题目大意
每次询问,给定
由此,问题转化为两种操作:
-
在平面上插入一条线段。
-
求所有与
x=c 相交的线段中交点y 坐标最大的一个。
这就是 李超线段树 的模板题了。由于题目中有小数,可以将所有时间乘以
100pts
注意到
参考代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define double long double
using namespace std;
const int maxn=100010;
const int inf=1e9+1;
const int ddd=20000010;
const double g=9.8;
int m,cur;
char op[10];
double a,v,x,l,r;
struct seg
{
double a,b;
double f(double x){return x*a+b;}
}s[maxn];
int rt,cnt,lc[ddd],rc[ddd],id[ddd];
void update(int&o,int l,int r,int ql,int qr,int v)
{
if(r<ql||l>qr)return;
if(!o)o=++cnt;
if(ql<=l&&r<=qr)
{
if(!id[o])id[o]=v;
else
{
if(s[v].f(l/1000.0)>=s[id[o]].f(l/1000.0)&&s[v].f(r/1000.0)>=s[id[o]].f(r/1000.0)){id[o]=v;return;}
if(s[v].f(l/1000.0)<=s[id[o]].f(l/1000.0)&&s[v].f(r/1000.0)<=s[id[o]].f(r/1000.0))return;
if(l==r)return;
int mid=(l+r)>>1;
if(s[v].f(l/1000.0)>=s[id[o]].f(l/1000.0))
{
if(s[v].f(mid/1000.0)>=s[id[o]].f(mid/1000.0))update(rc[o],mid+1,r,ql,qr,id[o]),id[o]=v;
else update(lc[o],l,mid,ql,qr,v);
}
else
{
if(s[v].f(mid/1000.0)<=s[id[o]].f(mid/1000.0))update(rc[o],mid+1,r,ql,qr,v);
else update(lc[o],l,mid,ql,qr,id[o]),id[o]=v;
}
}
return;
}
int mid=(l+r)>>1;
update(lc[o],l,mid,ql,qr,v);
update(rc[o],mid+1,r,ql,qr,v);
}
int query(int o,int l,int r,int x)
{
if(!o)return 0;
if(l==r)return id[o];
int mid=(l+r)>>1,ans;
if(x<=mid)ans=query(lc[o],l,mid,x);
else ans=query(rc[o],mid+1,r,x);
if(!id[o])return ans;
if(!ans)return id[o];
if(s[id[o]].f(x/1000.0)>=s[ans].f(x/1000.0))return id[o];
return ans;
}
main()
{
scanf("%d",&m);
while(m--)
{
scanf("%s",op);
if(op[0]=='a')
{
cur++;
scanf("%Lf%Lf%Lf%Lf",&a,&v,&l,&r);
s[cur].a=v+g*l;s[cur].b=a-g/2*l*l-v*l;
update(rt,-inf,inf,(int)(l*1000.0),(int)(r*1000.0),cur);
}
else
{
scanf("%Lf",&x);
int t=query(rt,-inf,inf,(int)(x*1000.0));
if(!t)printf("Undefined\n");
else printf("%Lf\n",-g/2*x*x+s[t].a*x+s[t].b);
}
}
return 0;
}