給定乙個n元素陣列,你有m個操作,每次操作可以選擇乙個區間[li,ri],將這個區間內的數減少vi,你可以選擇其中一些進行操作,問你最後可以得到的最大值與最小值的差是多少?
因為每個操作是對於區間而言,我們不可能去遍歷每個區間,所以需要更好的策略。
又因為題中說的是最大值與最小值的差,所以我們可以考慮固定一端,選擇另一端。
於是,我們列舉每個位置i,然後選擇操作,讓i盡可能的小(也就是如果區間x包括了點i,我們就選擇區間x),這樣點i能夠到達理想的最小值,此時我們再查詢整個區間的最大值,就是一種可行的答案了,最後答案取所以位置的最大值就完了。
因為乙個點可能被很多個區間覆蓋,我們並不是暴力加,在從左往右遍歷的過程中,在每個區間的左端點l插入這個區間,在區間的右端點r+1處刪除這個區間,這樣每個區間只會被update兩次,就能更新到每個位置i啦。
#include using namespace std;
typedef long long ll;
const int maxn=2e5+10;
struct treenodetree[maxn<<2];
ll a[maxn];
void push_up(int root)
void build(int root,int l,int r)
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
push_up(root);
}void push_down(int root)
}void update(int root,int l,int r,int v)
push_down(root);
int mid=(tree[root].l+tree[root].r)>>1;
if(r<=mid)
else if(l>mid)
else
push_up(root);
}ll query(int root,int l,int r,int opt)
push_down(root);
int mid=(tree[root].l+tree[root].r)>>1;
if(r<=mid)
else if(l>mid)
else
else
}}struct segseg[maxn];
vectorl[maxn];
vectorr[maxn];
int cmp(const seg a,const seg b)
inline ll readll()
signed main()
build(1,1,n);
for(int i=1;i<=m;i++)
sort(seg+1,seg+m+1,cmp);
for(int i=1;i<=m;i++)
ll ans=0;
for(int i=1;i<=n;i++)
for(int j=0;jll now=query(1,i,i,2);
ll maxx=query(1,1,n,1);
ans=max(ans,maxx-now);
}printf("%lld\n",ans);
return 0;
}
牛客練習賽56 D 小翔和泰拉瑞亞(線段樹)
題目描述 小翔愛玩泰拉瑞亞 一天,他碰到了一幅地圖。這幅地圖可以分為n列,第i列的高度為hi,他認為這個地圖不好看,決定對它進行改造。小翔又學會了m個魔法,實施第i個魔法可以使地圖的第li列到第ri列每一列的高度減少wi,每個魔法只能實施一次,魔法的區間可能相交或包含。小翔認為,一幅地圖中最高的一列...
小翔和泰拉瑞亞
題目描述 小翔愛玩泰拉瑞亞 一天,他碰到了一幅地圖。這幅地圖可以分為n列,第i列的高度為hi,他認為這個地圖不好看,決定對它進行改造。小翔又學會了m個魔法,實施第i個魔法可以使地圖的第li列到第ri列每一列的高度減少wi,每個魔法只能實施一次,魔法的區間可能相交或包含。小翔認為,一幅地圖中最高的一列...
牛客練習賽56 小魂和他的數列
題目鏈結 給出乙個數列,讓求長度為k的嚴格遞增子串行有多少個 怎麼做呢?顯然dp 這個是很好想的 for int i 1 i n i for int i 2 i m i 這個dp顯然tle 所以 當時沒有做出來。做到這裡不會做了。想不到怎麼優化。顯然在最裡面的那個迴圈的作用是字首和 小於a i 的位...