【CF1556E】Equilibrium

题目

题目链接:https://codeforces.com/contest/1556/problem/E
给定两个长度为 (n) 的序列 (a,b)。一次操作可以选择一个严格递增序列 (q_1,q_2,cdots,q_k)(要求 (k) 为偶数),让 (a_{q_1},a_{q_3},cdots,a_{q_{k-1}}) 全部加 (1)(a_{q_2},a_{q_4},cdots,a_{q_{k}}) 全部减 (1)
(Q) 次询问,每次询问给定 (l,r),求区间 ([l,r]) 这一段区间至少需要多少次操作才能把 (a_{l}sim a_r) 变为 (b_lsim b_r)
(n,Qleq 10^5)

思路

首先令 (a_i= b_i-a_i)。不难发现,对于正数,我们只可能让他减;负数只可能加;零肯定不会选。这个画一下很容易证明。
那么把正数 (v) 看作连续 (v)(,负数 (v) 看作连续 (-v)),那么对于一次询问 (l,r),它是可能的当且仅当 (lsim r) 这一段是一个合法的括号序列,并且答案就是最大的括号嵌套数。
考虑类似区间最大子段和一般的线段树做法,维护一棵线段树,对于线段树上每一个区间维护 (ans,cnt1,cnt2),分别表示这个区间内最大括号嵌套层数;剩余没有匹配的左 / 右括号数量。
区间合并的时候就判断一下左区间的 ( 数量和右区间的 ) 数量的大小。
时间复杂度 (O(Qlog n))

代码

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;

const int N=100010;
int Q,n,a[N],b[N];

struct node
{
	ll ans,cnt1,cnt2;
};

node merge(node x,node y)
{
	node z;
	if (x.cnt1>y.cnt2)
	{
		z.ans=max(x.ans,y.ans+x.cnt1-y.cnt2);
		z.cnt1=x.cnt1+y.cnt1-y.cnt2;
		z.cnt2=x.cnt2;
	}
	else
	{
		z.ans=max(y.ans,x.ans+y.cnt2-x.cnt1);
		z.cnt1=y.cnt1;
		z.cnt2=x.cnt2+y.cnt2-x.cnt1;
	}
	return z;
}

struct SegTree
{
	node f[N*4];
	
	void update(int x,int l,int r,int k,ll v)
	{
		if (l==r)
		{
			f[x]=(node){abs(v),max(0LL,v),max(0LL,-v)};
			return;
		}
		int mid=(l+r)>>1;
		if (k<=mid) update(x*2,l,mid,k,v);
			else update(x*2+1,mid+1,r,k,v);
		f[x]=merge(f[x*2],f[x*2+1]);
	}
	
	node query(int x,int l,int r,int ql,int qr)
	{
		if (ql==l && qr==r) return f[x];
		int mid=(l+r)>>1;
		if (qr<=mid) return query(x*2,l,mid,ql,qr);
		if (ql>mid) return query(x*2+1,mid+1,r,ql,qr);
		return merge(query(x*2,l,mid,ql,mid),query(x*2+1,mid+1,r,mid+1,qr));
	}
}seg;

int main()
{
	scanf("%d%d",&n,&Q);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	for (int i=1;i<=n;i++) scanf("%d",&b[i]);
	for (int i=1;i<=n;i++) seg.update(1,1,n,i,b[i]-a[i]);
	while (Q--)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		node res=seg.query(1,1,n,l,r);
		if (res.cnt1 || res.cnt2) cout<<"-1
";
			else cout<<res.ans<<"
";
	}
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/15206081.html