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; }