Cf1108E2 xdtree

枚举minn+维护变化+线段树区间最大

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

int n,m;
int a[100005];

int rg[305][2];
vector<int>in[100005],out[100005];

struct node
{
    int l,r;
    int fg,maxn;
}tr[100005*5];

node up(node rt,node ls,node rs)
{
    node ntr=rt;
    ntr.maxn=max(ls.maxn,rs.maxn);
    return ntr;
}

void build(int i,int l,int r)
{
    tr[i].l=l;tr[i].r=r;tr[i].fg=0;
    if(l==r)
    {
        tr[i].maxn=a[l];
    }
    else
    {
        int mid=(l+r)/2;
        build(i*2,l,mid);
        build(i*2+1,mid+1,r);
        tr[i]=up(tr[i],tr[i*2],tr[i*2+1]);
    }
    return ;
}

void down(int i)
{
    if(tr[i].fg!=0)
    {
        tr[i*2].fg+=tr[i].fg;tr[i*2].maxn+=tr[i].fg;
        tr[i*2+1].fg+=tr[i].fg;tr[i*2+1].maxn+=tr[i].fg;
        tr[i].fg=0;
    }
}
void update(int i,int l,int r,int ql,int qr,int w)
{
    if(l==ql && r==qr)
    {
        tr[i].maxn+=w;tr[i].fg+=w;
    }
    else
    {
        down(i);
        int mid=(l+r)/2;
        if(qr<=mid)
            update(i*2,l,mid,ql,qr,w);
        else if(ql>mid)
            update(i*2+1,mid+1,r,ql,qr,w);
        else
        {
            update(i*2,l,mid,ql,mid,w);
            update(i*2+1,mid+1,r,mid+1,qr,w);
        }
        tr[i]=up(tr[i],tr[i*2],tr[i*2+1]);
    }
}

node query(int i,int l,int r,int ql,int qr)
{
    if(l==ql && r==qr)
    {
        return tr[i];
    }
    else
    {
        down(i);
        int mid=(l+r)/2;
        if(qr<=mid)
            return query(i*2,l,mid,ql,qr);
        else if(ql>mid)
            return query(i*2+1,mid+1,r,ql,qr);
        else
        {
            node tp1=query(i*2,l,mid,ql,mid);
            node tp2=query(i*2+1,mid+1,r,mid+1,qr);
            node tp3=up(tp3,tp1,tp2);
            return tp3;
        }
    }
}
int main() {

    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&rg[i][0],&rg[i][1]),in[rg[i][0]].push_back(i),out[rg[i][1]+1].push_back(i);
        
        int ansid=1,ans=0;
        int sum=0;

        build(1,1,n);
        for(int i=1;i<=n;i++)
        {
            int len=in[i].size();
            for(int j=0;j<len;j++)
            {
                int id=in[i][j];
                int l=rg[id][0];
                int r=rg[id][1];
                update(1,1,n,l,r,-1);
                sum--;
            }

            len=out[i].size();
            for(int j=0;j<len;j++)
            {
                int id=out[i][j];
                int l=rg[id][0];
                int r=rg[id][1];
                update(1,1,n,l,r,1);
                sum++;
            }

            int maxn=query(1,1,n,1,n).maxn;
            int tans=(maxn-(a[i]+sum));
            if(tans>ans)
            {
                ans=tans;ansid=i;
            }
        }

        printf("%d\n",ans);
        int ct=0;int anss[305];
        for(int i=1;i<=m;i++)
        {
            if(rg[i][0]<=ansid && rg[i][1]>=ansid)
            {
                anss[ct++]=i;
            }
        }
        printf("%d\n",ct);
        for(int i=0;i<ct;i++)
        {
            printf("%d ",anss[i]);
        }
        printf("\n");
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值