lgP5324 [BJOI2019]删数
题目给定的操作等价于:
覆盖\([i - cnt_i + 1 , i]\)
最后答案就是 \([S-T] - [S-T]中覆盖了的长度 = ans\)
单点修改很好做,直接修改一下并集就好了
但是区间整体 +/- 1就不是很好办了
直接平移一下区间就好了
注意到 如果一个 区间的右端点在 当前确定的区间右边 那么不会对答案产生贡献
/*
区间加减,区间并 
*/
#include<bits/stdc++.h>
#define MAXN 1000005
typedef long long ll;
using namespace std;
ll n,m;
ll a[MAXN],cnt[MAXN];
ll lim = 450000+5;
struct node{ll mi,ans,cnt,ad;}t[MAXN * 5];
void up(int rt){
	t[rt].mi = min(t[rt << 1].mi , t[rt << 1 | 1].mi);
	t[rt].cnt = ((t[rt << 1].mi == t[rt].mi) ? t[rt << 1].cnt : 0) + ((t[rt << 1 | 1].mi == t[rt].mi) ? t[rt << 1 | 1].cnt : 0);//没被覆盖的区间 
	t[rt].ans = t[rt << 1].ans + t[rt << 1 | 1].ans;
}
void build(int rt , int l , int r){
	if(l == r)return (void)(t[rt].ans = t[rt].cnt = 1);
	int mid = (l + r) >> 1;
	build(rt << 1 , l , mid);
	build(rt << 1 | 1 , mid + 1 , r);
	up(rt);
}
void change(int rt , int c){
	t[rt].mi += c;
	t[rt].ans = (t[rt].mi == 0 ? t[rt].cnt : 0);
	t[rt].ad += c;
}
void push_down(int rt){
	if(!t[rt].ad)return;
	change(rt << 1 , t[rt].ad);
	change(rt << 1 | 1 , t[rt].ad);
	t[rt].ad = 0;
}
void update(int rt , int l , int r , int x , int y , int z){
	if(r < x || l > y)return;
	if(x <= l && r <= y){
		change(rt , z);
		return;
	}
	push_down(rt);
	int mid = (l + r) >> 1;
	update(rt << 1 , l , mid , x , y , z);
	update(rt << 1 | 1 , mid + 1 , r , x , y , z);
	up(rt);
}
int que(int rt , int l , int r , int x , int y){
	if(r < x || l > y)return 0;
	if(x <= l && r <= y)return t[rt].ans;
	push_down(rt);
	int mid = (l + r) >> 1 , zz = 0;
	zz = zz + que(rt << 1 , l , mid , x , y);
	zz = zz + que(rt << 1 | 1 , mid + 1 , r , x , y);
	up(rt);
	return zz;
}
void dec(int x , int v){
	int k = x - cnt[x] + 1 - (v > 0);
	update(1 , 1 , lim , k , k , v);
	cnt[x] += v;
}
int main(){
	scanf("%d%d" , &n , &m);
	int ST = 1 + 150000;
	build(1 , 1 , lim);
	for(int i = 1 ; i <= n ; i++){
		scanf("%lld" , &a[i]) , a[i] += ST;	
		dec(a[i] , 1);
	}
	ll p,x;
	while(m--){
		scanf("%lld%lld" , &p , &x);
		if(!p){
			if(x <= 0){
				ST++;
				int pos = ST + n;
				if(cnt[pos])update(1 , 1 , lim , pos - cnt[pos] + 1 , pos , 1);
			}
			else{
				int pos = ST + n;
				if(cnt[pos])update(1 , 1 , lim , pos - cnt[pos] + 1 , pos , -1);
				ST--;
			}
		}
		else{
			if(a[p] <= ST + n)dec(a[p] , -1);
			else cnt[a[p]]--;
			a[p] = x + ST;
			if(a[p] <= ST + n)dec(a[p] , 1);
			else cnt[a[p]]++;
		}
		cout<<que(1 , 1 , lim , ST + 1 , ST + n)<<endl;
	}
}
学习了一下 区间求并的写法,之前自己的写法太拉胯了
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号