线段树分治套凸包
每个机器人在多次修改之间的贡献是不同的,因为这个一次函数被修改。显然要线段树分治。
我们需要在线段树上维护凸壳,刚开始我以为要用动态凸包的那套理论。后来才知道直接在外面给所有一次函数排序,做凸壳就能是线性的了。。。我真智障
这个代码常数太大,在UOJ上排倒二,你们还是别(另)看(请)了(高)吧(明)。
#include
#include
#define N 500005
#define cmax(u,v) (u)<(v)?(u)=(v):0
using namespace std;
namespace ziqian
{
typedef long long ll;
const int INF = 1<<29;
int in()
{
int r = 0, p = 0; char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) if(c == '-') p = 1;
for(; c >='0' && c <='9'; c = getchar()) r = r * 10 + c - '0';
return p?-r:r;
}
struct line
{
int k; ll b;
ll f(int x) {return (ll)k * x + b;}
double operator * (line l){return (double)(b-l.b)/(l.k-k);}
}con[N];
struct modify
{
line L; int l, r;
} mod[N*2], tmp_mod[N*2];
ll ans[N];
int n, m, last[N], tot, qcnt, q[N];
char s[10];
double px[N];
bool cmp(modify a, modify b)
{
return a.L.k < b.L.k;
}
void solve(int ml, int mr, int ql, int qr)
{
if(ml > mr) return;
int top = 0;
for(int i = ml; i <= mr; i++)
if(mod[i].l <= ql && qr <= mod[i].r)
{
line L = mod[i].L;
while(top > 1)
{
if(con[top].k == L.k)
{
if(con[top].b <= L.b) --top;
else break;
}
else if(L * con[top] <= con[top-1] * con[top])--top;
else break;
}
if(!(con[top].k == L.k && con[top].b >= L.b))con[++top] = L;
}
for(int i = 1; i < top; i++) px[i] = con[i] * con[i+1];
px[top] = INF;
for(int i = ql, cur = 1; cur <= top && i <= qr; i++)
{
for(; px[cur] < q[i] && cur <= top; ++cur);
if(cur > top)break;
ll tmp = con[cur].f(q[i]);
cmax(ans[i], tmp);
}
if(ql == qr)return;
int mid = (ql+qr)>>1, nl = ml-1, nr = mr+1;
for(int i = ml; i <= mr; i++)
{
if(mod[i].l <= mid && (mod[i].l > ql || qr > mod[i].r)) ++nl, tmp_mod[nl] = mod[i];
else --nr, tmp_mod[nr] = mod[i];
}
for(int i = nr, ii = (nr+mr)/2; i <= ii; i++) swap(tmp_mod[i], tmp_mod[nr+mr-i]);
for(int i = ml; i <= mr; i++) mod[i] = tmp_mod[i];
solve(ml, nl, ql, mid);
int ll = nl+1, tmpcnt = ml-1;
for(int i = ml; i <= nl || ll <= mr; )
{
if(ll > mr ||( i <= nl && mod[i].L.k < mod[ll].L.k)) tmp_mod[++tmpcnt] = mod[i], i++;
else tmp_mod[++tmpcnt] = mod[ll], ll++;
}
for(int i = ml; i <= mr; i++) mod[i] = tmp_mod[i];
nl = ml - 1; nr = mr + 1;
for(int i = ml; i <= mr; i++)
{
if(mod[i].r > mid && (mod[i].l > ql || qr > mod[i].r)) ++nl, tmp_mod[nl] = mod[i];
else --nr, tmp_mod[nr] = mod[i];
}
for(int i = nr, ii = (nr+mr)/2; i <= ii; i++) swap(tmp_mod[i], tmp_mod[nr+mr-i]);
for(int i = ml; i <= mr; i++) mod[i] = tmp_mod[i];
solve(ml, nl, mid+1,qr);
ll = nl+1, tmpcnt = ml-1;
for(int i = ml; i <= nl || ll <= mr; )
{
if(ll > mr ||( i <= nl && mod[i].L.k < mod[ll].L.k)) tmp_mod[++tmpcnt] = mod[i], i++;
else tmp_mod[++tmpcnt] = mod[ll], ll++;
}
for(int i = ml; i <= mr; i++) mod[i] = tmp_mod[i];
}
void main()
{
n = in(), m = in();
for(int i = 1; i <= n; i++)
{
mod[++tot] = (modify){(line){0, in()}, 1, -1};
last[i] = tot;
}
for(int i = 1, t; i <= m; i++)
{
t = in(); scanf("%s",s);
if(s[0] == 'c')
{
int pos = in(), kk = in();
mod[last[pos]].r = qcnt;
mod[++tot] = (modify){(line){kk, mod[last[pos]].L.f(t) - (ll)kk * t}, qcnt+1, -1};
last[pos] = tot;
}
else
q[++qcnt] = t;
}
for(int i = 1; i <= tot; i++) if(mod[i].r == -1) mod[i].r = qcnt;
for(int i = 1; i <= tot; i++)
if(mod[i].l > mod[i].r)
mod[i] = mod[tot--];
sort(mod+1,mod+1+tot,cmp);
solve(1, tot, 1, qcnt);
for(int i = 1; i <= tot; i++)
mod[i].L.k *= -1, mod[i].L.b *= -1;
sort(mod+1,mod+1+tot,cmp);
solve(1, tot, 1, qcnt);
for(int i = 1; i <= qcnt; i++)
printf("%lld\n",ans[i]);
}
}
int main()
{
ziqian::main();
}