zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    java基础知识(一)- 数据类型
    Java基础知识-去重
    java基础知识-冒泡排序
    Java排序方法sort的使用详解
    Java面试题-字符串操作
    Map.Entry遍历Map
    Java中String的用法
    Java循环控制语句-switch
    API文档打开显示'已取消到该网页的导航'的解决方法
    CentOS6.5 安装snort
  • 原文地址:https://www.cnblogs.com/stoorz/p/15206081.html
Copyright © 2011-2022 走看看