Codeforces Round #535 E2-Array and Segments (Hard version)

题意:

给你一个数列和一些区间,让你选择一些区间(选择的区间中的数都减一),

求最后最大值与最小值的差值最大,并输出选择的区间

思路:

在n=300的时候,我们是枚举每个数作为最小值,应用所有覆盖它的区间,并且没

次都更行差值的最大值。

但是这里的n=1e5,所以我们不能用O(n*n*m),但是我们看到这里的m=300

所以可以从m入手,枚举区间,就是记录每个区间的两个端点,利用差分的思想,

来枚举更新最大值

这里说一下为什么枚举最小值,因为如果最大值也在这个区间则抵消,如果没在则

更好

#include<bits/stdc++.h>
using namespace std;
#define MAX 100005
int n,m;
vector<int>add[MAX],sub[MAX],a(MAX);
vector<pair<int,int > >b(MAX);

void change(int l,int r,int x)
{
    for(int i=l;i<=r;i++)
    {
        a[i]+=x;
    }
}
int main()
{
  while(~scanf("%d %d",&n,&m))
  {
      for(int i=0;i<m;i++) sub[i].clear();
      for(int i=0;i<m;i++) add[i].clear();
      for(int i=0;i<n;i++)
      {
          scanf("%d",&a[i]);
      }
      for(int i=0;i<m;i++)
      {
          scanf("%d %d",&b[i].first,&b[i].second);
          b[i].first--;
          b[i].second--;
          sub[b[i].first].push_back(i);
          add[b[i].second+1].push_back(i);
      }
      int minn,maxn;
       minn=maxn=a[0];//注意这里不要习惯把minn=INF,maxn=0,因为a数组元素可能为负数,比如-1,这样ans=1,容易出错
      for(int i=1;i<n;i++)
      {
          maxn=max(maxn,a[i]);
          minn=min(minn,a[i]);
      }
      int ans=maxn-minn;
      int c=-1;
      for(int i=0;i<n;i++)
      {
          //应用覆盖的区间
          for(int j=0;j<sub[i].size();j++)
          {
              int ind=sub[i][j];
              change(b[ind].first,b[ind].second,-1);
          }
          //消除之前的区间
          for(int j=0;j<add[i].size();j++)
          {
              int ind=add[i][j];
              change(b[ind].first,b[ind].second,1);
          }
          int minn=maxn=a[0];
          if(add[i].size()||sub[i].size())
          {
              for(int j=1;j<n;j++)
              {
                  maxn=max(maxn,a[j]);
                  minn=min(minn,a[j]);
              }
              if(maxn-minn>ans)
              {
                  ans=maxn-minn;
                  c=i;
              }
          }
      }
      int len=0;
      int mask[MAX];
      for(int i=0;i<m;i++)
      {
          if(b[i].first<=c&&c<=b[i].second)
          {
              mask[len++]=i;
          }
      }
      printf("%d\n",ans);
      printf("%d\n",len);
      for(int i=0;i<len;i++)
      {
          printf("%d ",mask[i]+1);
      }
  }
  return 0;
}

原文地址:https://www.cnblogs.com/zhgyki/p/10328239.html

时间: 2024-08-30 17:38:55

Codeforces Round #535 E2-Array and Segments (Hard version)的相关文章

CF #535 (Div. 3) E2 Array and Segments (Hard version) 利用线段树进行区间转移

传送门 题意:    有m个区间,n个a[ i ] , 选择若干个区间,使得整个数组中的最大值和最小值的差值最小.n<=1e5,m<=300; 思路: 可以知道每个i,如果一个区间包含这个点,就让这个区间发挥作用.枚举每个i,找到最大值即可. 当然这个复杂度不对,我们可以通过线段树保存数组的最大值和最小值,每次区间在左端点发挥作用,在右端点去掉作用. #include <algorithm> #include <iterator> #include <iostre

Codeforces Round #535 (Div. 3) 题解

Codeforces Round #535 (Div. 3) 题目总链接:https://codeforces.com/contest/1108 太懒了啊~好久之前的我现在才更新,赶紧补上吧,不能漏掉了. A. Two distinct points 题意: 给出两个区间的左右边界,输出两个数,满足两个数分别在两个区间内且这两个数不相等. 题解: 直接输出左端点然后判断一下就行了. 代码如下: #include <bits/stdc++.h> using namespace std; type

Codeforces 1108E2 Array and Segments (Hard version) 差分, 暴力

Codeforces 1108E2 E2. Array and Segments (Hard version) Description: The only difference between easy and hard versions is a number of elements in the array. You are given an array \(a\) consisting of \(n\) integers. The value of the \(i\)-th element

Educational Codeforces Round 21 D. Array Division

题目链接:Educational Codeforces Round 21 D. Array Division 题意: 给你n个数,现在你可以改变1<=个数的位置,然后问你是否存在有一个k,使得sum(a[i])(1<=i<=k)==sum(a[j])(k+1<=j<=n) 题解: 分析: 如果需要将一个数移动,无非就是将这个数从第一部分移到第二部分,或者从第二部分移到第一部分. 所以,我们只需要开两个map来记录一下两部分有哪些数. 当两部分的差值/2等于其中一部分的一个数时

Codeforces Round #504 D. Array Restoration

Codeforces Round #504 D. Array Restoration 题目描述:有一个长度为\(n\)的序列\(a\),有\(q\)次操作,第\(i\)次选择一个区间,将区间里的数全部改为\(i\),序列\(a\)的每个位置至少被改一次.得到最终的序列,然后将序列里的某些位置变成\(0\),输出一种可能的置零之前的最终序列,或无解. solution 求出每种数字最长的染色区间,按这个区间染色,记下没出现的数字.染色后如果存在\(0\)联通块,则用没出现的数字从大到小染色(一个联

Codeforces Round #535 (Div. 3)小上分记

Codeforces Round #535 (Div. 3)小上分记 前言 被拉去买新年衣服了,导致半小时后才进场. 虽然做了4道题,但是rating还是涨得不多. 用predictor看了rating变化后心灰意冷,不看E题了. A ...800的难度. B 本来还在想要不要用什么STL.后来发现直接用桶就行了.然后就可以水过了. C 题意差点理解不了. 就6种情况都去考虑一下,找最小代价的即可.不要考虑少了. 每次都是\(O(n)\)的,所以能搞. D 贪心地换字母即可. E 坑.待填. 原

B类-Codeforces Round #535 (Div. 3)C. Nice Garland

Codeforces Round #535 (Div. 3)C. Nice Garland 题意: 由'R', 'G' and 'B' 三个字母组成的一个字符串,每两个相同的字母需要相差3,找出最小需要交换次数. 分析: 这个字符串的长度大于等于3的时候,一定是RBG这三个字符的某一个排列的循环.RBG一共最多有6种排列方式{"RGB","RBG","BGR","BRG","GRB","GBR&q

[Codeforces Round #622 (Div. 2)] - C2. Skyscrapers (hard version) (单调栈)

[Codeforces Round #622 (Div. 2)] - C2. Skyscrapers (hard version) (单调栈) C2. Skyscrapers (hard version) time limit per test 3 seconds memory limit per test 512 megabytes input standard input output standard output This is a harder version of the probl

Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version) 单调栈

Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version) 问题 传送门 我是参考了这篇题解传送门,然后按着思路做出了的(但大佬题解中的sumr[]数组操作我没看懂,然后自己改了改). 摘抄: 维护峰值最优 找左右边的第一个比自己小的元素,维护前缀和,找最大的峰值 l[i]:用单调栈维护左边第一个比它小的数 r[i]:用单调栈维护右边第一个比它小的数 suml[i]:左边的前缀和 sumr[i]:右边的前缀和 然后遍历一遍数组,找到

Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version)(单调栈,递推)

Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version) 题意: 你是一名建筑工程师,现给出 n 幢建筑的预计建设高度,你想建成峰状,如: 1 2 3 2 1 → 1 2 3 2 1 1 2 3 1 2 → 1 2 3 1 1 8 10 6 → 8 10 6 10 6 8 → 10 6 6 问所有建筑的高度和最大为多少. 思路: 单调递增栈栈顶存储以当前点为峰的单侧最低高度下标,另存储以每个点为峰的左右最大高度和. #includ