codeforces#1108E2. Array and Segments (线段树+扫描线)

 

题目链接:

http://codeforces.com/contest/1108/problem/E2

题意:

给出$n$个数和$m$个操作

每个操作是下标为$l$到$r$的数减一

选出某些操作,使$n$个数的最大值减最小值最大

数据范围:

$1 \le n \le 10^5$

$0 \le m \le 300$

$-10^6 \le a_i \le 10^6$

分析: 

假设选择第$i$位置作为最小值,那么我们选取所有包含$i$的区间可以得到选择第$i$位置为最小值的最佳答案

第一步,我们从$1$到$n$枚举最小值的位置

第二步,我们用扫描线来添加和减少题目给出的区间影响,例如最小值为$i$时,我们要让所有的包含i区间的操作生效

第三步,计算以$i$为最小值时的最优解

ac代码:

#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=1e5+10;
const int maxm=300+10;
const ll mod=1e9+7;
int ans=-1,inde,tree[maxn*4],lazy[maxn*4],num[maxn],n;
pa quer[maxm];
vector<pa>ve[maxn];
vector<int>ve2;
void build(int st,int en,int rt)
{
    if(st==en)
    {
        tree[rt]=num[st];
        return ;
    }
    int md=(st+en)/2;
    build(st,md,rt*2);
    build(md+1,en,rt*2+1);
    tree[rt]=max(tree[rt*2],tree[rt*2+1]);
}
void update(int l,int r,int x,int st,int en,int rt)
{
    if(l>en||r<st)return ;
    if(l<=st&&r>=en)
    {
        lazy[rt]+=x;
        tree[rt]+=x;
        return ;
    }
    if(lazy[rt])
    {
        int v=lazy[rt];
        lazy[rt*2]+=v;
        lazy[rt*2+1]+=v;
        tree[rt*2]+=v;
        tree[rt*2+1]+=v;
        lazy[rt]=0;
    }
    int md=(st+en)/2;
    update(l,r,x,st,md,rt*2);
    update(l,r,x,md+1,en,rt*2+1);
    tree[rt]=max(tree[rt*2],tree[rt*2+1]);
}
int Quer(int x,int st,int en,int rt)
{
    if(st==en)
        return tree[rt];
    if(lazy[rt])
    {
        int v=lazy[rt];
        lazy[rt*2]+=v;
        lazy[rt*2+1]+=v;
        tree[rt*2]+=v;
        tree[rt*2+1]+=v;
        lazy[rt]=0;
    }
    int md=(st+en)/2;
    int res;
    if(x<=md)res=Quer(x,st,md,rt*2);
    else res=Quer(x,md+1,en,rt*2+1);
    tree[rt]=max(tree[rt*2],tree[rt*2+1]);
    return res;
}
int main()
{
    int q;
    scanf("%d %d",&n,&q);
    for(int i=1;i<=n;i++)
        scanf("%d",&num[i]);
    build(1,n,1);
    for(int i=1;i<=q;i++)
    {
        int l,r;
        scanf("%d %d",&l,&r);
        quer[i].first=l;
        quer[i].second=r;
        ve[l].push_back(make_pair(i,-1));
        ve[r+1].push_back(make_pair(i,+1));
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<ve[i].size();j++)
        {
            int v=ve[i][j].first;
            int add=ve[i][j].second;
            update(quer[v].first,quer[v].second,add,1,n,1);
        }
        int res=tree[1]-Quer(i,1,n,1);
        if(res>ans)
        {
            inde=i;
            ans=res;
        }
    }
    printf("%d\n",ans);
    int res=0;
    for(int i=1;i<=q;i++)
        if(inde>=quer[i].first&&inde<=quer[i].second)
            ve2.push_back(i);
    printf("%d\n",ve2.size());
    for(int i=0;i<ve2.size();i++)
        printf("%d%c",ve2[i]," \n"[i==ve2.size()-1]);
    return 0;
}

  

posted @ 2019-07-11 20:36  czh~  阅读(185)  评论(0编辑  收藏  举报