2019 徐州网络赛 B E 线段树

B. so easy

题意:初始你有 n 个数, 1 到 n 。你有两个操作 1 x 代表删除 x , 2 x 代表查询第一个大于等于 x 的数

题解: n 很大, 所以不能建 1 到 n 的线段树, 但是执行的操作只有1e6, 对每次操作选取 x, x+1, 将选取的点离散化建线段树,对于每次操作 1 , 删除 x, 对于操作 2 , 查询第一个大于等于 x 的数

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10;
typedef long long ll;

int n, q;
struct node{
	int op, x;
}e[N];
int b[N];

int Max[4*N];
void up(int id, int l, int r, int pos, int v){
	if(l==r){
		Max[id] = v;
		return ;
	}
	int mid = (l+r)/2;
	int ls = id<<1, rs = id<<1|1;
	if(pos <= mid) up(ls, l, mid, pos, v);
	else up(rs, mid+1, r, pos, v);
	Max[id] = max(Max[ls], Max[rs]);
}

int qu(int id,int l,int r,int k)
{
	if(l==r)
		return l;
	int mid=l+r>>1;
	if(Max[id<<1]>=k) return qu(id<<1,l,mid,k);
	else return qu(id<<1|1,mid+1,r,k);
}
int main(){
	scanf("%d%d",&n, &q);
	int cnt = 0;
	for(int i = 1 ; i <= q; i++){
		scanf("%d%d",&e[i].op, &e[i].x);
		b[++cnt] = e[i].x;
		b[++cnt] = e[i].x+1;
	}
	sort(b+1, b+1+cnt);
	int len = unique(b+1, b+1+cnt) - b - 1;
	for(int i = 1; i <= len; i++){
		up(1, 1, len, i, i);
	}
	for(int i = 1; i <= q; i++){
		int pos = lower_bound(b+1, b+1+len, e[i].x) - b;
		if(e[i].op == 1){
			up(1, 1, len, pos, 0);
		}
		else{
			printf("%d\n",b[qu(1, 1, len, pos)]);
		}
	}
	return 0;
}

E. XKC's basketball team

题意:CXKNB!!!找到 大于等于 ai+m 的 aj ,索引 j 最大 (j > i), 如果没有答案为 -1

题解:线段树维护 i ~n 的最大值, 倒着建树, 先插入点 n 然后 n-1, n-2。。。。插入 i 前, 查询 i+1 ~ n 大于等于 ai+m 线段树内最小点下标(只要满足大于等于ai+m,我就往左查,否则往右),保证最后找到的 aj 索引最大。(线段树上索引与实际aj的索引相反, 因为倒着建树)

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+10;
typedef long long ll;
int n, m;
int a[N];
vector<int> ans;
int Max[4*N];
void up(int id, int l, int r, int pos, int v){
	if(l==r){
		Max[id] = v;
		return ;
	}
	int mid = (l+r)/2;
	int ls = id<<1, rs = id<<1|1;
	if(pos <= mid) up(ls, l, mid, pos, v);
	else up(rs, mid+1, r, pos, v);
	Max[id] = max(Max[ls], Max[rs]);
}

int qu(int id,int l,int r,ll k)
{
	if(l==r)
		return l;
	int mid=l+r>>1;
	if(Max[id<<1]>=k) return qu(id<<1,l,mid,k);
	else return qu(id<<1|1,mid+1,r,k);
}

int main(){
	scanf("%d%d", &n, &m);
	for(int i = n ; i >= 1; i--){
		scanf("%d", &a[i]);
	}
	ans.push_back(-1);
	up(1, 1, n, 1, a[1]);
	for(int i = 2; i <= n; i++){
		ll tmp = a[i] + m;
		int pos = qu(1, 1, n, tmp);
		if(i-pos-1 >= 0)ans.push_back(i-pos-1);
		else ans.push_back(-1);
		up(1, 1, n, i, a[i]);
	}
	for(int i = ans.size()-1; i >= 0; i--){
		printf("%d%c", ans[i], i != 0?' ':'\n');
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值