Liveddd's Blog

愛にできることはまだあるかい

CF678F Lena and Queries

线段树分治。

没有修改的情况下就是李超线段树模板。考虑加上修改的情况,尝试线段树分治,把每条直线出现时间段放在线段树上,而对于线段树上每个节点都开一棵李超线段树即可。这样时间复杂度为 $\mathcal O(n\log^2 n)$。

似乎并不够优,我们并不需要每一时刻维护每个位置的最优取值。考虑斜率优化,将查询的 $x$ 按照 $x$ 进行排序,直线 $kx+b$ 按照 $k$ 排序。$k_1<k_2$,若 $k_1x+b_1<k_2x+b_2$,则容易得到:

单调队列维护即可,时间复杂度为 $\mathcal O(n\log n)$。注意要先全部排序在放在线段树上,不然复杂度会变为 $\mathcal O(n\log^2 n)$。

while 写成 if 调了 1h,哈哈哈哈哈哈。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define fi first
#define se second
using namespace std;
using ll=long long;
using PII=pair<int,int>;
const int N=5e5+10;
const ll INF=2e18;
template<class T>
inline void read(T &x)
{
x=0;bool f=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(f)x=~x+1;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1)
{
read(x),read(x1...);
}
int T,n,m;
PII line[N],pos[N],q[N];
int L[N],R[N];
int id[N];
ll ans[N];
struct Node
{
vector<PII>p,q;
}tr[N<<2];
template<class T>
inline void ckmax(T &x,T y){x=x>y?x:y;}
void modify(int x,int l,int r,int ql,int qr,const PII &k)
{
if(l>=ql&&r<=qr)return tr[x].p.push_back(k);
int mid=l+r>>1;
if(ql<=mid)modify(x<<1,l,mid,ql,qr,k);
if(qr>mid)modify(x<<1|1,mid+1,r,ql,qr,k);
}
void modify(int x,int l,int r,int pos,const PII &k)
{
tr[x].q.push_back(k);
if(l==r)return ;
int mid=l+r>>1;
if(pos<=mid)modify(x<<1,l,mid,pos,k);
else modify(x<<1|1,mid+1,r,pos,k);
}

void solve(int x,int l,int r)
{
if(tr[x].q.empty())return ;
int h=1,t=0;
for(auto now:tr[x].p)
{
while(h<t&&1ll*(q[t-1].se-q[t].se)*(now.fi-q[t].fi)>=1ll*(q[t].se-now.se)*(q[t].fi-q[t-1].fi))t--;
q[++t]=now;
}
for(auto now:tr[x].q)
{
while(h<t&&1ll*now.fi*(q[h+1].fi-q[h].fi)>=(q[h].se-q[h+1].se))h++;
if(h<=t)ckmax(ans[now.se],1ll*now.fi*q[h].fi+q[h].se);
}
if(l==r)return ans[l]>-INF?printf("%lld\n",ans[l]):puts("EMPTY SET"),void();
int mid=l+r>>1;
solve(x<<1,l,mid),solve(x<<1|1,mid+1,r);
}
inline bool cmp(const int &x,const int &y){return line[x].fi==line[y].fi?line[x].se<line[y].se:line[x].fi<line[y].fi;}
int main()
{
read(T);
for(int i=1;i<=T;i++)
{
int op;
read(op);
if(op==1)
{
n++;
read(line[n].fi,line[n].se);
id[L[n]=i]=n;
}
if(op==2)
{
int x;
read(x);
R[id[x]]=i-1;
}
if(op==3)
{
m++;
read(pos[m].fi);
pos[m].se=i;
}
}
for(int i=1;i<=n;i++)if(!R[i])R[i]=T;
for(int i=1;i<=n;i++)id[i]=i;
sort(id+1,id+1+n,cmp);
sort(pos+1,pos+1+m);
for(int i=1,x;i<=n;i++)x=id[i],modify(1,1,T,L[x],R[x],line[x]);
for(int i=1;i<=m;i++)modify(1,1,T,pos[i].se,pos[i]);
memset(ans,-0x7f,sizeof(ans));
solve(1,1,T);
return 0;
}