P5324 [BJOI2019] 删数
思路
先考虑不带修改的
序列答案显然与其顺序无关,注意到等于 \(n\) 的数必定被选到,所以还剩 \(n - cnt_n\) 个,然后 \(n - cnt_n\) 被选,重复循环即可。
那我们如何求要修改的个数呢?
其实很显然,你每一步覆盖不到的部分显然需要别的地方重复覆盖的点去补,所以考虑每个值垒成一根柱子,实际上就是将所有柱子向左推以后的未覆盖的点个数。
然后考虑怎么带修改:
- 对于单点修改,由于只涉及两个值,直接修改掉然后给桶分别加减就行。
- 对于区间修改,考虑到这玩意实际上等价于限定了一个查询的区间范围,然后全体加减就等价于移动这个查询范围(+1左移,-1右移)
每次只需要在左移右移的时候删除/加入一下右边的的临界区间覆盖区间即可。
然后我们需要微调一下单点修改,如果当前修改的值在右端点左侧,那就修改,否则改下桶即可,等到后面右端点到这里再修改就行了
具体维护的话,我们的数据结构需要支持区间加,区间查等于0的个数,所以用线段树维护最小值 \(mn\) ,最小值的数量 \(cnt\) ,区间的答案 \(res\) ,以及懒标记 \(lzy\) 即可。
为了方便维护避免负数情况,我们可以把查询范围左端点的初值赋为1.5e5这样就不会炸了。
Code
// By wnn
#include<bits/stdc++.h>
//#include<ext/pb_ds/assoc_container.hpp>
//#include<ext/pb_ds/priority_queue.hpp>
//#include<ext/pb_ds/exception.hpp>
//#include<ext/pb_ds/hash_policy.hpp>
//#include<ext/pb_ds/list_update_policy.hpp>
//#include<ext/pb_ds/tree_policy.hpp>
//#include<ext/pb_ds/trie_policy.hpp>
//using namespace __gnu_pbds;
using namespace std;
#define int long long
namespace OI{
namespace Simple_name{
#define myfreopen freopen(\".in\", \"r\", stdin),freopen(\".out\", \"w\", stdout)
using ll = long long;
using db = double;
using ull = unsigned long long;
using pdd = pair<db, db>;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
#define pq priority_queue
#define rep(i,a,b) for(int i=(a),i##_end=(b);i<=i##_end;++i)
#define dep(i,a,b) for(int i=(a),i##_end=(b);i>=i##_end;--i)
#define x1 x_1
#define y1 y_1
#define fir first
#define sec second
#define pb push_back
#define I_love_you ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
}
using namespace Simple_name;
namespace Val{
#define eps 1e-9
#define inf32 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3fll
#define mod1 (int)(1e9 + 7)
#define mod2 998244353
#define PI acos(-1.0)
#define db_e (double)(2.71828182845904523536028)
}
using namespace Val;
namespace Function{
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
#define mid(l, r) ((l + r) >> 1)
#define debug(x) cerr<<#x<<\"=\"<<x<<endl
#define log(x, y) (log2(y) / log2(x)) // 以x为底y的对数
#define WA cerr << \"Wrong Answer\" << endl
#define init_inf32(x) memset(x, 0x3f, sizeof(x))
#define init_inf64(x) memset(x, 0x3fll, sizeof(x))
#define init_0(x) memset(x, 0, sizeof(x))
#define Dec(x) fixed << setprecision(x)
ll pw(ll x, ll P, ll mod = mod1){
ll ret = 1;
while(P){
if(P & 1) ret = ret * x % mod;
x = x * x % mod; P >>= 1;
}
return ret;
}
}
using namespace Function;
}
using namespace OI;
// Init rnd()
mt19937 rnd(time(0) ^ clock());
// Constants
const int dx[4] = {1, -1, 0, 0};
const int dy[4] = {0, 0, 1, -1};
const int N = 5e5 + 5, V = 1.5e5, MX = V * 3 + 5;
int n, m;
int a[N], cnt[N];
int wdl = V + 1;
#define wdr (wdl + n)
class Segment{
private:
struct Tree{
int mn, cnt;
int res, lzy;
} t[N << 2];
#define mn(x) t[x].mn
#define cnt(x) t[x].cnt
#define res(x) t[x].res
#define lzy(x) t[x].lzy
void up(int x){
mn(x) = min(mn(ls(x)), mn(rs(x)));
cnt(x) = (mn(ls(x)) == mn(x)) * cnt(ls(x)) + (mn(rs(x)) == mn(x)) * cnt(rs(x));
res(x) = res(ls(x)) + res(rs(x));
}
void push(int x, int val){
mn(x) += val;
res(x) = (mn(x) == 0) * cnt(x);
lzy(x) += val;
}
void down(int x){
if(lzy(x)){
push(ls(x), lzy(x));
push(rs(x), lzy(x));
lzy(x) = 0;
}
}
public:
void build(int x = 1, int l = 1, int r = MX){
if(l == r){
cnt(x) = 1; res(x) = 1;
return ;
}
int mid = mid(l, r);
build(ls(x), l, mid);
build(rs(x), mid + 1, r);
up(x);
}
void modify(int ql, int qr, int val, int x = 1, int l = 1, int r = MX){
if(ql > r || qr < l) return ;
if(ql <= l && qr >= r){
push(x, val);
return ;
}
down(x); int mid = mid(l, r);
modify(ql, qr, val, ls(x), l, mid);
modify(ql, qr, val, rs(x), mid + 1, r);
up(x);
}
int query(int ql, int qr, int x = 1, int l = 1, int r = MX){
if(ql <= l && qr >= r){
return res(x);
} down(x);
int mid = mid(l, r);
if(qr <= mid) return query(ql, qr, ls(x), l, mid);
if(ql > mid) return query(ql, qr, rs(x), mid + 1, r);
return query(ql, qr, ls(x), l, mid) + query(ql, qr, rs(x), mid + 1, r);
}
void add(int x, int fu = 1){
int New = x - cnt[x] + 1 - (fu == 1);
modify(New, New, fu);
cnt[x] += fu;
}
} T;
void init(){
cin >> n >> m;
T.build();
rep(i, 1, n){
cin >> a[i];
a[i] += wdl; T.add(a[i], 1);
}
while(m--){
int p, x; cin >> p >> x;
if(p != 0){
if(a[p] <= wdr) T.add(a[p], -1);
else --cnt[a[p]];
a[p] = x + wdl;
if(a[p] <= wdr) T.add(a[p], 1);
else ++cnt[a[p]];
}else{
// 右边覆盖去除/加入,左边影响不到不用管
if(x == 1){
if(cnt[wdr]) T.modify(wdr - cnt[wdr] + 1, wdr, -1);
--wdl;
}else{
++wdl;
if(cnt[wdr]) T.modify(wdr - cnt[wdr] + 1, wdr, 1);
}
}
cout << T.query(wdl + 1, wdr) << "\n";
}
}
void solve(){
}
signed main(){
// myfreopen;
I_love_you;
init();
int T = 1;
// cin >> T;
while(T--){
solve();
}
return 0;
}
/*things to check:
* Will it MLE?
* Is array big enough?
* Do you need long long?
* Is inf big enough?
* max or min?
* Yes,No or YES,NO?
* Is there anything extra to output?
* Did you Countershoot?
* Have you measured the limit data?
* More measurements should be cleared!!!
*/

浙公网安备 33010602011771号