题解 草莓蛋糕
- 带加带删,加好加删不好删的题记得线段树分治
关于不带删的那档分:
贡献是 \(\max(a_c+b_c, a_y+b_y)\)
拆一个出来,变成 \(\max(a_c-a_y+b_c, b_y)+a_y\)
发现 \(a_c-a_y\) 只和物品 \(a\) 有关,令 \(v=a_c-a_y\)
再拆一个出来,变成 \(\max(v, b_y-b_c)+b_c\),线段树根据 \(v\) 和 \(b_y-b_c\) 的大小关系查不同的值即可
然后正解:
分类讨论拆 max
令 \(a_c+b_c\geqslant a_y+b_y\)
移项得 \(a_c-a_y\geqslant b_y-b_c\)
对于两个商店,分别令特征值 \(h=a_c-a_y\) 和 \(h=b_y-b_c\)
开权值线段树,将每个物品的信息放到其特征值的位置上,只需要维护 \(mina, minc\)
合并的时候稍微讨论一下就可以,注意特征值相等的时候要特殊处理
带删的话线段树叶子节点开一个 multiset 即可
复杂度 \(O(n\log n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define fir first
#define sec second
#define ll long long
#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int q;
struct ques{int op, d, c, y;}que[N];
int uni[N], h[N], cnt[2], usiz;
#define tl(p) tl[p]
#define tr(p) tr[p]
multiset<int> s[N][2][2];
int tl[N<<2], tr[N<<2], dat[N<<2];
pair<int, int> mina[N<<2], minb[N<<2];
inline void pushup(int p) {
// cout<<"pushup: "<<p<<' '<<tl(p)<<' '<<tr(p)<<endl;
mina[p]={min(mina[p<<1].fir, mina[p<<1|1].fir), min(mina[p<<1].sec, mina[p<<1|1].sec)};
minb[p]={min(minb[p<<1].fir, minb[p<<1|1].fir), min(minb[p<<1].sec, minb[p<<1|1].sec)};
// cout<<dat[p<<1]<<' '<<dat[p<<1|1]<<endl;
dat[p]=min(dat[p<<1], dat[p<<1|1]);
// cout<<minb[p<<1].fir+mina[p<<1|1].fir<<endl;
dat[p]=min(dat[p], minb[p<<1].fir+mina[p<<1|1].fir);
// cout<<mina[p<<1].sec+minb[p<<1|1].sec<<endl;
dat[p]=min(dat[p], mina[p<<1].sec+minb[p<<1|1].sec);
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r; dat[p]=INT_MAX;
mina[p]=minb[p]={INT_MAX, INT_MAX};
if (l==r) return ;
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void upd(int p, int pos, pair<int, int> val, int op) {
if (tl(p)==tr(p)) {
bool side=op&2;
if (op&1) s[tl(p)][side][0].insert(val.fir), s[tl(p)][side][1].insert(val.sec);
else s[tl(p)][side][0].erase(val.fir), s[tl(p)][side][1].erase(val.sec);
if (!side) mina[p]=s[tl(p)][side][0].size()?(pair<int, int>){*s[tl(p)][side][0].begin(), *s[tl(p)][side][1].begin()}:(pair<int, int>){INT_MAX, INT_MAX};
else minb[p]=s[tl(p)][side][0].size()?(pair<int, int>){*s[tl(p)][side][0].begin(), *s[tl(p)][side][1].begin()}:(pair<int, int>){INT_MAX, INT_MAX};
if (s[tl(p)][0][0].size()&&s[tl(p)][1][0].size())
dat[p]=max(*s[tl(p)][0][0].begin()+*s[tl(p)][1][0].begin(), *s[tl(p)][0][1].begin()+*s[tl(p)][1][1].begin());
else dat[p]=INT_MAX;
return ;
}
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) upd(p<<1, pos, val, op);
else upd(p<<1|1, pos, val, op);
pushup(p);
}
signed main()
{
freopen("cake.in", "r", stdin);
freopen("cake.out", "w", stdout);
q=read();
for (int i=1; i<=q; ++i) {
que[i].op=read(), que[i].d=read(), que[i].c=read(), que[i].y=read();
if (!que[i].d) uni[++usiz]=h[i]=que[i].c-que[i].y;
else uni[++usiz]=h[i]=que[i].y-que[i].c;
}
sort(uni+1, uni+usiz+1);
usiz=unique(uni+1, uni+usiz+1)-uni-1;
for (int i=1; i<=q; ++i) h[i]=lower_bound(uni+1, uni+usiz+1, h[i])-uni;
build(1, 1, usiz);
for (int i=1; i<=q; ++i) {
upd(1, h[i], {que[i].c, que[i].y}, (que[i].d<<1)|que[i].op);
printf("%lld\n", dat[1]==INT_MAX?-1:dat[1]);
}
return 0;
}