题解 草莓蛋糕

传送门

  • 带加带删,加好加删不好删的题记得线段树分治

关于不带删的那档分:
贡献是 \(\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;
}
posted @ 2022-07-20 15:36  Administrator-09  阅读(3)  评论(0编辑  收藏  举报