题解:
对于二维坐标系,两种操作
• 1. 插入一条射线,以x=1为起点
• 2. 查询横坐标为X (整数)时所有射线y值的最大值
• 1 ≤ n, q ≤ 1e5
•新加入一条射线可能会影响若干区间
•即最后区间[a,b]的答案可能由”折线”组成
•这也正是本题难点
•考虑标记永久化。即对于线段树上的每个点 (代表一个区间)除非由严格更优的射线出现,否则不删除此线段 (新线段直接下传)
•按照斜率及区间中点处取值分四种情况讨论• 画图说明
•如何计算答案?(注意题目是单点询问)
•答案即为X在线段树中对应的叶子到根路径上所有的点答案取max
• O(n logn)
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<math.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<functional>
using namespace std;
typedef long long ll;
#define inf 1000000000
#define mod 1000000007
#define maxn 500005
#define PI 3.1415926
#define lowbit(x) (x&-x)
#define eps 1e-9
bool flag[maxn * 4];
double a[maxn * 4], b[maxn * 4], ans;
double work(double x, double y, double xx, double yy)
{
return (yy - y) / (x - xx);
}
void insert(int id, int l, int r, double bb, double k)
{
if (!flag[id])
a[id] = k, b[id] = bb, flag[id] = 1;
else
{
double t1 = 1.0*k*l + bb, t2 = 1.0*k*r + bb;
double tt1 = 1.0*a[id] * l + b[id], tt2 = 1.0*a[id] * r + b[id];
if (t1 <= tt1 && t2 <= tt2)
return;
else if (t1 > tt1 && t2 > tt2)
a[id] = k, b[id] = bb;
else
{
int mid = (l + r) / 2;
double y = work(k, bb, a[id], b[id]);
if (t1 >= tt1)
{
if (y <= mid)
insert(id * 2, l, mid, bb, k);
else
insert(id * 2 + 1, mid + 1, r, b[id], a[id]), a[id] = k, b[id] = bb;
}
else
{
if (y > mid)
insert(id * 2 + 1, mid + 1, r, bb, k);
else
insert(id * 2, l, mid, b[id], a[id]), a[id] = k, b[id] = bb;
}
}
}
}
void query(int id, int l, int r, int x)
{
if (flag[id])
ans = max(ans, a[id] * (double)x + b[id]);
if (l == r) return;
int mid = (l + r) / 2;
if (x <= mid)
query(id * 2, l, mid, x);
else
query(id * 2 + 1, mid + 1, r, x);
}
int main(void)
{
double x, y;
int q, t, mx = -1;
scanf("%d", &q);
while (q--)
{
scanf("%d", &t);
if (t == 1)
{
scanf("%lf%lf", &x, &y);
insert(1, 1, maxn - 5, x - y, y);
}
else
{
int xx;
scanf("%d", &xx);ans = 0;query(1, 1, maxn - 5, xx);
printf("%lld\n", (ll)floor(ans / 100.0));
}
}
return 0;
}