H. Ksyusha and the Loaded Set

https://codeforces.com/contest/2000/problem/H div3 H

一开始看就感觉要维护一些比较有趣的量

看了一下数据范围ai<=2e6,k<=2e6

似乎可以直接开一个线段树来表示是否存在集合当中

我们开4e6维护每个数字是否存在,ai=2e6时候k=2e6,最大是4e6

存在的就是1,不存在的就是0,询问就转化为长度为大于等于k的全0子段输出最左边的索引

但用感觉不好维护

实际上从左到右找就可以线段树二分

我们维护最长全0子段长度即可

再二分,考虑左子树和右子树可以合并的情况

然后每次建4e6会tle

我们考虑每次完成样例取消之前的影响

用集合模拟样例的操作,最后取消之前的影响

// Problem: H. Ksyusha and the Loaded Set
// Contest: Codeforces - Codeforces Round 966 (Div. 3)
// URL: https://codeforces.com/contest/2000/problem/H
// Memory Limit: 512 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<set>
using namespace std;
const int N=3e6+9;
//线段树
struct SEG{
    #define INF 4000001
    #define ll long long
    #define tl(id) (id<<1)
    #define tr(id) (id<<1|1)
    #define li inline
    struct node{
        int l,r,len;
        //0
        ll lmx,rmx,tmx;
    }seg[N<<2];
    li void pushup(node &id,node &l,node &r){
    	id.lmx=l.lmx+r.lmx*(l.lmx==l.len);
    	id.rmx=r.rmx+l.rmx*(r.rmx==r.len);
    	id.tmx=max(l.tmx,max(r.tmx,l.rmx+r.lmx));
    }
    #define pushup(id) pushup(seg[id],seg[tl(id)],seg[tr(id)]);
    li int inrange(int L,int R,int l,int r){return l<=L && R<=r;}
    li int outofrange(int L,int R,int l,int r){return L>r || R<l;}
    li void build(const int id,int l,int r){
       	seg[id]={l,r,r-l+1};
        if(l==r){
        	seg[id]={l,r,1,1,1,1};
            return;
        }
        int mid=(l+r)>>1;
        build(tl(id),l,mid);
        build(tr(id),mid+1,r);
        pushup(id);
    }
    li ll query(int id,int l,int r,int v){
    	if(l==r){
    		return l;
		}
		int mid=(l+r)>>1;
		if(seg[tl(id)].tmx>=v){
			return query(tl(id),l,mid,v);
		}
		if(seg[tl(id)].rmx+seg[tr(id)].lmx>=v){
			return seg[tl(id)].r-seg[tl(id)].rmx+1;
		}
		if(seg[tr(id)].tmx>=v){
			return query(tr(id),mid+1,r,v);
		}
		return 0;
    }
   	li void update(int id,int l,int r,int pos,int v){
   		if(l==r){
   			if(v==1){
   				seg[id]={l,r,1,0,0,0};
   			}
   			if(v==0){
   				seg[id]={l,r,1,1,1,1};
   			}
   			return;
   		}
   		int mid=(l+r)>>1;
   		if(mid>=pos){
   			update(tl(id),l,mid,pos,v);
   		}else{
   			update(tr(id),mid+1,r,pos,v);
   		}
   		pushup(id);
   	}
}t;
void solve(){
	set<int> st;
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		st.insert(x);
		t.update(1,1,INF,x,1);
	}
	int m;
	cin>>m;
	for(int i=1;i<=m;i++){
		char op;
		int x;
		cin>>op>>x;
		if(op=='+'){
			st.insert(x);
			t.update(1,1,INF,x,1);
		}else if(op=='-'){
			st.erase(x);
			t.update(1,1,INF,x,0);
		}else{
			cout<<t.query(1,1,INF,x)<<" ";
		}
	}
	for(auto & i : st){
		t.update(1,1,INF,i,0);
	}
	cout<<'\n';
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	t.build(1,1,INF);
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值