Codeforces 1108 E2(线段树+思维)
傳送們
題意:
給你一個長度為nnn的數列bbb、以及mmm個區間。
你可以選取111個或多個這樣的區間aia_iai?,使得令區間aia_iai?所對應的所有值bib_ibi?都減111。你最終要使得max?i=1nbi?min?i=1nbi\max\limits_{i=1}^{n}b_i - \min\limits_{i=1}^{n}b_ii=1maxn?bi??i=1minn?bi?
最大。
問你方案數以及最大值。
題目分析:
在E1E1E1中,我們可以通過這個題中優美的性質,對于每一個區間aia_iai?,通過枚舉在這個區間的以及不在這個區間的兩個點,我們就可以用O(b2m)O(b^2m)O(b2m)的時間復雜度進行求解。
但是在這個題中,nnn的范圍在10510^5105的級別,因此我們需要用一些數據結構進行優化。
我們考慮這幾種情況,對于每一個區間操作,如果區間內的最小值恰好在要更新的區間內,而最大值不在,則此時答案必定更優;如果最小值和最大值恰在要更新的區間內,則答案不變;如果最大值在而最小值不在,則答案必定更差。
至此,我們可以發現,要使得答案不會變差,當且僅當最小值恰好在要更新的區間內。
但是我們目前并不知道哪一個點作為最小值點更優,因此我們可以枚舉最小值點的位置pospospos。根據我們之前的分析,最小值點能夠防止答案變差,因此那些能夠把我們所枚舉的pospospos包含的區間必定要更新。而一個區間要包含一個點,則這個區間至少是那些以該點為起始點的區間。因此我們只需要在枚舉最小值點位置的過程中,不斷的進行區間?1-1?1即可。
而我們需要注意的是,在我們枚舉的過程中,倘若我們之前更新的某一個區間不能包含當前的位置,我們需要把之前的影響消去,否則會導致將區間的最大值也減111,導致答案不正確。因此,我們只需要在之前枚舉的過程的最后,把以當前位置pospospos為結尾的所有區間的影響消去即可。
因為存在區間更新以及區間求最大值,因此我們可以用線段樹進行維護。
總的時間復雜度為O(nlogn)O(nlogn)O(nlogn)
#include <bits/stdc++.h> #define maxn 100005 using namespace std; typedef pair<int,int>pll; pll q[maxn]; int a[maxn]; vector<int>vec1[maxn]; vector<int>vec2[maxn]; vector<int>res;struct Tree{int add,maxx; }tr[maxn<<2]; void push_up(int rt){tr[rt].maxx=max(tr[rt<<1].maxx,tr[rt<<1|1].maxx); } void push_down(int rt){if(tr[rt].add){tr[rt<<1].maxx+=tr[rt].add;tr[rt<<1|1].maxx+=tr[rt].add;tr[rt<<1].add+=tr[rt].add;tr[rt<<1|1].add+=tr[rt].add;tr[rt].add=0;} } void build(int l,int r,int rt){if(l==r){tr[rt].maxx=a[l];return ;}int mid=(l+r)>>1;build(l,mid,rt<<1);build(mid+1,r,rt<<1|1);push_up(rt); } void update(int L,int R,int l,int r,int rt,int C){if(L<=l&&R>=r){tr[rt].add+=C;tr[rt].maxx+=C;return ;}int mid=(l+r)>>1;push_down(rt);if(L<=mid) update(L,R,l,mid,rt<<1,C);if(R>mid) update(L,R,mid+1,r,rt<<1|1,C);push_up(rt); } int query(int L,int R,int l,int r,int rt){if(L<=l&&R>=r){return tr[rt].maxx;}int mid=(l+r)>>1;push_down(rt);int maxx=-0x3f3f3f3f;if(L<=mid) return max(maxx,query(L,R,l,mid,rt<<1));if(R>mid) return max(maxx,query(L,R,mid+1,r,rt<<1|1));push_up(rt); }int main() {int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);build(1,n,1);for(int i=1;i<=m;i++){scanf("%d%d",&q[i].first,&q[i].second);vec1[q[i].first].push_back(q[i].second);//以該點為起點的區間的右端點vec2[q[i].second].push_back(q[i].first);//以該點為終點的區間的左短點}int maxx=-0x3f3f3f3f;int pos=0;for(int i=1;i<=n;i++){int tmp=a[i];for(int j=0;j<vec1[i].size();j++){update(i,vec1[i][j],1,n,1,-1);//區間更新-1}int res=query(1,n,1,n,1)-query(i,i,1,n,1);//區間求和,等于區間最大值-當前值(最小值)if(maxx<res){maxx=res;pos=i;}for(int j=0;j<vec2[i].size();j++){update(vec2[i][j],i,1,n,1,1);}}cout<<maxx<<endl;int cnt=0;for(int i=1;i<=m;i++){if(q[i].first<=pos&&pos<=q[i].second){res.push_back(i);}cnt++;}cout<<res.size()<<endl;for(auto it:res){cout<<it<<" ";}puts(""); }轉載于:https://www.cnblogs.com/Chen-Jr/p/11007167.html
總結
以上是生活随笔為你收集整理的Codeforces 1108 E2(线段树+思维)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mybatisplus逻辑删除
- 下一篇: +=运算符的问题