D. Multiset(权值线段树 or 树状数组+二分)Educational Codeforces Round 87 (Rated for Div. 2)

D. Multiset(权值线段树 or 树状数组+二分)Educational Codeforces Round 87 (Rated for Div. 2)_第1张图片
D. Multiset(权值线段树 or 树状数组+二分)Educational Codeforces Round 87 (Rated for Div. 2)_第2张图片
题目大意:
给你一个长度为 n n n的序列,以及 q q q次询问 q i qi qi,如果 q i > 0 qi>0 qi>0,在序列中插入 q i qi qi,如果 q i < 0 qi<0 qi<0,在序列中删除第 ∣ q i ∣ |qi| qi大的数,问你 q q q询问后,如果序列中为空,输出 0 0 0即可,否则输出序列中任意一个数即可。
思路:
所有操作无非就是删除第 k k k大数,增加第 k k k大数,我们可以用桶排序的思路建立线段树我们称为它为权值线段树,这个题 n = 1 e 6 n=1e6 n=1e6用权值线段树时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)是可以过的,但是结构体开不了会超空间这里要换一种存储方式,然后就是线段树的单点更新,单点询问操作(都很简单),还有权值线段树的第 k k k大操作(相当于前缀和也很简单)。
代码:

#include
using namespace std;

const int maxn = 1e6 + 10;
int tree[maxn << 2];
void update(int rt,int x,int l,int r){
	if(l == r && l == x){
		tree[rt]++;
		return ;
	}
	int mid = l + r >> 1;
	if(x <= mid)update(rt << 1,x,l,mid);
	else update(rt << 1 | 1,x,mid + 1,r);
	tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
bool check(int rt,int id,int l,int r){
	if(l == r && l == id){
		if(tree[rt] > 0)return true;
		else return false;
	}
	int mid = l + r >> 1;
	if(id <= mid)return check(rt << 1,id,l,mid);
	else return check(rt << 1 | 1,id,mid + 1,r);
}
void kth(int rt,int k,int l,int r){
	if(l == r){
		tree[rt]--;return;
	}
	int mid = l + r >> 1;
	if(tree[rt << 1] >= k)kth(rt << 1,k,l,mid);
	else kth(rt << 1 | 1,k - tree[rt << 1],mid + 1,r);
	tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
void solved(){
	int n,q;scanf("%d%d",&n,&q);
	for(int i = 1; i <= n; i++){
		int x;scanf("%d",&x); 
		update(1,x,1,n);
	}
	for(int i = 1; i <= q; i++){
		int x;scanf("%d",&x);
		if(x > 0)update(1,x,1,n);
		else {
			x *= -1;kth(1,x,1,n);
		}
	}
	if(tree[1] <= 0){
		printf("0\n");
	}else{
		for(int i = 1; i <= n; i++){
			if(check(1,i,1,n)){
				cout<<i<<endl;break;
			}
		}
	}
}
int main(){
	solved();
	return 0;
}

数组数组做法,其实和桶排序类似。
代码:

#include
using namespace std;

const int maxn = 1e6 + 10;
struct bit{
	int c[maxn];
	int lowbit(int x){
		return x & -x;
	}
	void update(int x,int v = 1){
		for(; x <= maxn; x += lowbit(x)){
			c[x] += v;
		}
	} 
	int query(int x){
		int s = 0;
		for(; x ; x -= lowbit(x)){
			s += c[x];
		}
		return s;
	}
}BIT;
void solved(){
	int n,q;scanf("%d%d",&n,&q);
	for(int i = 1; i <= n; i++){
		int x;scanf("%d",&x);BIT.update(x);
	}
	for(int i = 1; i <= q; i++){
		int x;scanf("%d",&x);
		if(x > 0)BIT.update(x);
		else{
			x *= -1;
			int l = 1,r = n;
			while(l < r){
				int mid = l + r >> 1;
				if(BIT.query(mid) >= x)r = mid;
				else l = mid + 1;
			}
			BIT.update(r,-1);
		}
	}
	int ans = BIT.query(n);
	if(ans <= 0){
		cout<<"0"<<endl;
	}else{
		for(int i = 1; i <= n ; i++){
			if(BIT.query(i) - BIT.query(i - 1) > 0){
				cout<<i<<endl;break;
			}
		}
	}
}
int main(){
	solved();
	return 0;
} 

你可能感兴趣的:(思维题,线段树)