CF EDU-162 (已更新:C)

mono-4 / 2024-02-24 / 原文

CF-EDU-162(已更新:C)

结果上看还不坏,但赛时写题过程十分若只(⊙﹏⊙)

C

赛时想到了求区间和的思路,可能是比赛前还在补线段树的题——我居然在半个小时里把线段树和树状数组都写了一次(而且交上去wa了),然后才想到用前缀和做……

分析

题意得要想明白,特别要结合样例来看,是说对于数组a从a[l]到a[r],如果存在数组b满足区间[l,r]内:

  1. 和相同
  2. a[i]!=b[i]
  3. b[i]>0

由1,2可知,,,直接说结论:要保证a[i]!=b[i]且和相同,意味着我们只能转移a[i]的权值来使a[i]相对原来的值发生变化

只要权值发生变化就可以了

那具体每个a[i]是怎样变化?自然是可以加可以减,但是第3个条件使得对于权值为1的a[i],它们的值只能增加,这个增加量我们称为"必要增加量",且它只能来自其它权值不为1的a[i]的减少量,我们称为"最大减少量",因此,只要使得区间内最大减少量——(最大为)所有(a[i]-1)之和大于等于必要增加量——(最小为)1的个数就可以了

操作

我的做法是赋值再求和,如果a[i]为1,将其赋值为-1,否则,a[i]-=1,这样一来,原本as数组中的1权值变成了-1——变成了它对区间内必要增加量的贡献,其它树的权值减去了1——变成了它对区间内最大减少量的贡献.

这样新数组的区间和只要>=0即满足条件.

代码

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
#define lc p<<1
#define rc p<<1|1
const int N=3e5+5;
int a[N],p[N];
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
	int t,x,y,q,n,cnt=0,ans=0;cin>>t;
	while(t--){
		cin>>n>>q;
		mem(p);
		rep(i,1,n){
			cin>>x;
            //赋值再求和
			if(x==1) x-=2;
			else x--;
			p[i]=p[i-1]+x;
		}
		while(q--){
			cin>>x>>y;
			if(x==y){
				cout<<"NO"<<endl;
				continue;
			}
			if(p[y]-p[x-1]>=0) cout<<"YES";
			else cout<<"NO";
			cout<<endl;
		}
	}
	return 0;
}