Codeforces Round#489 div2E Nastya and King-Shamans (线段树+暴力剪枝)

转载请注明出处:http://tokitsukaze.live/

题目链接:http://codeforces.com/problemset/problem/992/E


题意:给一个序列a,q次操作。每次操作单点修改。每次操作后,询问序列a中有没有一个位置满足a[i]=bit[i-1],如果有,随便输出一个位置,如果没有输出-1。其中bit为前缀和数组。


题解:
容易想到建立线段树维护a[i]-bit[i-1],问题就转化成查询线段树内值为0的位置。记录一个区间最大值maxx,查询时,如果这个区间maxx小于0,说明这个区间内的数全都不满足,直接剪枝,否则一直查询到叶子节点。

看上去很暴力,其实想想是可行的。因为如果要避开这个剪枝,a[i]-bit[i-1]必须大于0(如果等于0的话,也能很快走到叶子节点),那么这个序列假设a[1]=0,那么a[1]就至少为1,a[2]至少为2,a[3]至少为4,以此类推。也就是说,最多走过log个叶子节点,一定能得出答案。

代码:

 

#include<bits/stdc++.h>
#define rep(i, j, k) for (int i=j; i<k; i++)
#define pii pair<int, int> 
#define fi first
#define se second
#define ll long long 
using namespace std;
const ll mod = 1e9+7;
const int maxn = 1e6+6;
ll a[maxn], tag[maxn], diff[maxn], p[maxn], ps[maxn];
int n, q, x, v;
void build(int o, int l, int r){
	if (l==r) {
		a[o] = diff[l];
		return; 
	}
	int mid = l + r >> 1;
	build(o<<1, l, mid); build(o<<1|1, mid+1, r);
	a[o] = max(a[o<<1], a[o<<1|1]);
}

void pushdown(int o){ 
	a[o<<1] += tag[o];
	a[o<<1|1] += tag[o];
	tag[o<<1] += tag[o];
	tag[o<<1|1] += tag[o];
	tag[o] = 0;
}

void update(int o, int l, int r, int ql, int qr, ll v){
	//printf("update %d %d %d %d %d %lld\n", o, l, r, ql, qr, v);
	if (ql<=l && qr>=r){
		a[o] += v;
		tag[o] += v;
		return;
	}
	pushdown(o);
	int mid = l + r >> 1;
	if (ql <= mid){
		update(o<<1, l, mid, ql, qr, v);
	}
	if (qr > mid){
		update(o<<1|1, mid+1, r, ql, qr, v);
	}
	a[o] = max(a[o<<1], a[o<<1|1]);
	//printf("a[%d] = %lld\n", o, a[o]);
}

int query(int o, int l, int r){
	//printf("up %d %d %d\n", o, l, r);
	if (l==r) {
		if (a[o] == 0) {
			//printf("!@#$%^query %d %d %d a[%d] = 0\n", o, l, r, l);
			return l;
		}
		else return -1;
	}
	pushdown(o);
	int mid = l + r >> 1, t1 = -1, t2 = -1;
	if (a[o<<1] >= 0) {
		t1 = query(o<<1, l, mid);
		if (t1 != -1) return t1;
	}
	if (a[o<<1|1] >= 0) t2 = query(o<<1|1, mid+1, r);
	return t2;
}
int main(){
	scanf("%d%d", &n, &q);

	rep(i, 1, n+1){
		scanf("%d", &p[i]);
		ps[i] = ps[i-1] + p[i];
		diff[i] = p[i] - ps[i-1]; 
	}
	build(1, 1, n);

	rep(i, 0, q){
		scanf("%d%d", &x, &v);
		v = v - p[x]; p[x] = p[x] + v;
		update(1, 1, n, x, x, v);
		if (x+1 <= n) update(1, 1, n, x+1, n, -v);
		printf("%d\n", query(1, 1, n));
	}

}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值