题解:CF1179C Serge and Dining Room
wangzichen20240101 · · 题解
这是我们提高组练习题单的一题。
我们设
那么显然,-1。
学生排队顺序不影响这个最高剩价。因为当两个学生交换,若本来学生 A 在学生 B 前,且 A 所持有的钱数少于 B 所持有的钱数。
若 B 能买到比 A 所持有的钱数更贵的菜品,那么交换顺序互不影响,否则,若 A、B 所购买的菜品两人都可以买,那么交换顺序后一定也是都可以买,且一定买原来的菜品。
因此我们就证明了学生顺序与答案无关这件事。
现在我们考虑如何维护这个函数值。
考虑用线段树维护。对于一盘价格
查询时看整棵树的最小值:如果最小值都不小于
当不存在以我们计算出的最右边的满足条件的
修改是简单的,我们只需去除旧的贡献,再加上新的贡献即可。维护方式同上。
时间复杂度为
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
const int MX = 1e6;
const int INF = 1e9;
int n,m,q;
int a[N],b[N];
int cnt[N];
namespace SEG{
int t[4 * N],tag[4 * N];
inline void addtag(int p,int d){
tag[p] += d;
t[p] += d;
}
inline void pushdown(int p){
if(tag[p]){
addtag(p * 2,tag[p]);
addtag(p * 2 + 1,tag[p]);
tag[p] = 0;
}
}
void change(int p,int l,int r,int lx,int rx,int d){
if(l >= lx && r <= rx){
addtag(p,d);
return;
}
int mid = (l + r) >> 1;
pushdown(p);
if(mid >= lx) change(p * 2,l,mid,lx,rx,d);
if(mid + 1 <= rx) change(p * 2 + 1,mid + 1,r,lx,rx,d);
t[p] = max(t[p * 2],t[p * 2 + 1]);
}
int ask(int p,int l,int r){
if(l == r) return l;
pushdown(p);
int mid = (l + r) >> 1;
if(t[p * 2 + 1] > 0) return ask(p * 2 + 1,mid + 1,r);
if(t[p * 2] > 0) return ask(p * 2,l,mid);
return -1;
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> n >> m;
SEG::change(1,1,MX,1,MX,-INF);
for(int i = 1;i <= n;++i){
cin >> a[i];
if(cnt[a[i]] == 0) SEG::change(1,1,MX,a[i],a[i],+INF);
cnt[a[i]]++;
SEG::change(1,1,MX,1,a[i],1);
}
for(int i = 1;i <= m;++i){
cin >> b[i];
SEG::change(1,1,MX,1,b[i],-1);
}
cin >> q;
while(q--){
int op,x,y;
cin >> op >> x >> y;
if(op == 1){
int old = a[x];
SEG::change(1,1,MX,1,old,-1);
cnt[old]--;
if(cnt[old] == 0) SEG::change(1,1,MX,old,old,-INF);
SEG::change(1,1,MX,1,y,1);
if(cnt[y] == 0) SEG::change(1,1,MX,y,y,INF);
cnt[y]++;
a[x] = y;
}
else{
SEG::change(1,1,MX,1,b[x],1);
b[x] = y;
SEG::change(1,1,MX,1,b[x],-1);
}
cout << SEG::ask(1,1,MX) << '\n';
}
return 0;
}