Deltix Round, Summer 2021 E. Equilibrium(线段树)

E. Equilibrium

题目

对两个长度相同的数组的区间发起q次询问,最少多少次操作可使它们ai = bi
给定操作为选择一段偶数子区间,其中第一个数组的奇数个自增一,第二个数组的偶数位自增一。

思路

从总体上考虑

  • 因为是选偶数区间,每次两数组的区间和的差总不变,所以询问区间的区间和一定要相等。

考虑每个子区间

  • 因为a只操作奇数位,b只操作偶数位
    1. aL > bL 肯定无解
    2. 又因为虽然每次操作区间差值不变,但如果把修改区间右移一位,可以使修改后,sumb-suma将减小1,所以在局部上 ,sumb>suma 是允许的,反之 suma>sumb 一定无解
  • 对于最小操作数的获取,因为每次操作独立并且最大可以使差值前缀和减少1 ,
    那么差值区间和最大值就是最少的操作次数。

由上可发现判断总和a,b差值的区间和得出,可以大致写出代码实现思路:

  • 获取a,b的差值的前缀和
  • 由于要获取区间最值,建立一个线段树解决
  • 得到的最值是前缀最值,转化到区间最值进行判断即可解决本题

PS:因为不涉及修改,所以没必要打lazy_tag。

AC代码

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define endl '\n'
//#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N =10 + 1e5, mod = 1e9 + 7;
ll a[N],b[N];
ll sum[N];
ll mn,mx;
int n,q;
struct Tree
{
	ll mn,mx;
}tr[N*4];
void push_up(int p ,int l,int r)
{
	tr[p].mn = min(tr[l].mn,tr[r].mn);
	tr[p].mx = max(tr[l].mx,tr[r].mx);
}
void build(int p = 1 ,int l =1,int r = n)
{
	if(l == r)
	{
		tr[p].mn = tr[p].mx = sum[l];
		return ;
	}
	int mid = l + r >> 1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	push_up(p,p<<1,p<<1|1);
}

void query(int L,int R,int l=1,int r=n,int p=1)
{
	if(L<=l&&r<=R)
	{
		mn = min(mn,tr[p].mn);
		mx = max(mx,tr[p].mx);
		return;
	}
	int mid = l + r >> 1;
	if(L<=mid) query(L,R,l,mid,p<<1);
	if(R>=mid+1) query(L,R,mid+1,r,p<<1|1);
}
void solve()
{    
	cin>>n>>q;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)cin>>b[i];
	for(int i=1;i<=n;i++)sum[i] = sum[i-1] +(b[i]-a[i]);

	build();

	while(q--)
	{
		int l,r;
		cin>>l>>r;
		mn = linf , mx = -linf;
		query(l,r);
		mn -= sum[l-1] , mx -= sum[l-1];
		if(mn < 0 || sum[r] - sum[l-1] !=0)
			cout << -1 <<endl;
		else cout << mx << endl;
	} 
}
signed main()
{
	ios::sync_with_stdio();cin.tie();cout.tie();

	solve();

	return 0;
}
上一篇:饥饿的奶牛(算是模板题了,求给出N段区间的最大长度和,且区间不能有重叠)


下一篇:题解 打表