P7560 [JOISC 2021 Day1] フードコート
posted on 2024-07-21 07:30:42 | under | source
lby 模拟赛出了这道题,非常高妙。
本题是区间改、单点查,其中区间修改不好处理,所以考虑转化为单点改、区间查。
离线下来,我们以时间轴建树、对编号进行扫描线。具体而言,将每个询问存在对应的编号上,然后从 \(1\) 到 \(n\) 扫描修改操作,在线段树上维护所有涉及到当前编号的修改。
这样一来,修改变得容易,考虑一次询问第 \(pos\) 个,必然对应线段树上一段前缀。
假如不存在删除操作越过下界 \(0\),那么只需要先求出该前缀所有删除之和 \(cnt\),那么找到第 \(cnt+pos\) 个人对应的加人操作即可。
假如越过了下界,那么我们找到最后一次越过下界的时间,此后正常处理即可。注意到人数前缀和最小值的位置恰好是最后一次越过下界的时间,原因显然,假如现在已经越过了下界,那么下一次到现在这些修改操作之和必须满足小于 \(0\) 才能再次越界,即单调递减。
关于怎么进行区间二分:由于该做法的“区间”一定是一段后缀 \([p,R]\),所以我们只需要跳过前面 \([1,p-1]\) 即可,具体而言,假如原本查询第 \(k\) 大,\([1,p-1]\) 之和为 \(cnt\),那么全局查询第 \(k+cnt\) 大即可。
代码
写的比较屎,但是居然一遍过了,蒟蒻十分震惊。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lt (u << 1)
#define rt (u << 1 | 1)
#define mid (l + r >> 1)
#define pir pair<int, int>
const int N = 5e5 + 5, inf = 1e10;
int n, m, T, opt, l, r, a, b, ans[N], ID[N], Lby;
struct node{int tim, x, id;};
vector<node> mod[N];
vector<node> ask[N];
namespace Sg_Tree1{
int s[N << 2][2], col[N << 2];
inline void psup(int u) {s[u][0] = s[lt][0] + s[rt][0], s[u][1] = s[lt][1] + s[rt][1];}
inline void build(int u, int l, int r){
if(l == r) {col[u] = l; return ;}
build(lt, l, mid), build(rt, mid + 1, r);
}
inline void upd(int u, int l, int r, int k, int p, int id){
if(l == r) {s[u][id] += p; return ;}
if(k <= mid) upd(lt, l, mid, k, p, id);
else upd(rt, mid + 1, r, k, p, id);
psup(u);
}
inline int fid(int u, int l, int r, int ll, int rr, int id){
if(ll > rr) return 0;
if(ll <= l && r <= rr) return s[u][id];
int res = 0;
if(ll <= mid) res += fid(lt, l, mid, ll, rr, id);
if(rr > mid) res += fid(rt, mid + 1, r, ll, rr, id);
return res;
}
inline int calc(int u, int l, int r, int val){
if(l == r) return l;
if(val <= s[lt][0]) return calc(lt, l, mid, val);
return calc(rt, mid + 1, r, val - s[lt][0]);
}
};
namespace Sg_Tree2{
int mi[N << 2], num[N << 2], tag[N << 2];
inline void psup(int u){
if(mi[rt] < mi[lt]) mi[u] = mi[rt], num[u] = num[rt];
else mi[u] = mi[lt], num[u] = num[lt];
}
inline void psdw(int u){
mi[lt] += tag[u], mi[rt] += tag[u];
tag[lt] += tag[u], tag[rt] += tag[u];
tag[u] = 0;
}
inline void build(int u, int l, int r){
if(l == r) {mi[u] = 0, num[u] = l; return ;}
build(lt, l, mid), build(rt, mid + 1, r);
psup(u);
}
inline void upd(int u, int l, int r, int ll, int rr, int p){
if(ll <= l && r <= rr) {mi[u] += p, tag[u] += p; return ;}
psdw(u);
if(ll <= mid) upd(lt, l, mid, ll, rr, p);
if(rr > mid) upd(rt, mid + 1, r, ll, rr, p);
psup(u);
}
inline pir fid(int u, int l, int r, int ll, int rr){
if(ll <= l && r <= rr) return {mi[u], num[u]};
psdw(u); pir res = {inf, inf};
if(ll <= mid) res = min(res, fid(lt, l, mid, ll, rr));
if(rr > mid) res = min(res, fid(rt, mid + 1, r, ll, rr));
psup(u);
return res;
}
};
signed main(){
cin >> n >> m >> T;
for(int i = 1; i <= T; ++i){
scanf("%lld", &opt);
if(opt == 1){
scanf("%lld%lld%lld%lld", &l, &r, &a, &b);
ID[i] = a;
mod[l].push_back({i, b, 0}), mod[r + 1].push_back({i, -b, 0});
}
if(opt == 2){
scanf("%lld%lld%lld", &l, &r, &b);
mod[l].push_back({i, b, 1}), mod[r + 1].push_back({i, -b, 1});
}
if(opt == 3){
scanf("%lld%lld", &a, &b);
ask[a].push_back({i, b, ++Lby});
}
}
Sg_Tree1::build(1, 1, T);
Sg_Tree2::build(1, 1, T);
for(int i = 1; i <= n; ++i){
for(auto lby : mod[i]){
int tim = lby.tim, x = lby.x, id = lby.id;
Sg_Tree1::upd(1, 1, T, tim, x, id);
Sg_Tree2::upd(1, 1, T, tim, T, x * (id == 0 ? 1 : -1));
}
for(auto lby : ask[i]){
int tim = lby.tim, x = lby.x, id = lby.id;
pir Mi = Sg_Tree2::fid(1, 1, T, 1, tim);
int mi = Mi.first, pos = Mi.second;
if(mi >= 0) pos = 1;
int val = x + Sg_Tree1::fid(1, 1, T, pos + 1, tim, 1) + Sg_Tree1::fid(1, 1, T, 1, pos - 1, 0);
if(Sg_Tree1::fid(1, 1, T, 1, tim, 0) < val) ans[id] = 0;
else ans[id] = Sg_Tree1::calc(1, 1, T, val);
}
}
for(int i = 1; i <= Lby; ++i) printf("%lld\n", ID[ans[i]]);
return 0;
}

浙公网安备 33010602011771号