CodeForces - 1326E Bombs(线段树+思维)
題目鏈接:點擊查看
題目大意:給出一個 n 的排列記為 p[ i ] ,現在有一個初始時為空的集合A,對于每個 i 遍歷 1 ~ n ,每次的操作如下:
最后的答案就是保留在集合中的最大值
接下來給出一個數組 q ,表示炸彈的位置,對于每個前綴炸彈給出答案,此處的前綴可以理解為:
題目分析:比賽時感覺是線段樹,但自己維護的線段樹無法動態維護炸彈,因為每次添加的炸彈位置都是有大有小的,所以后續添加的炸彈很有可能會影響前面的決策,最后也是實力不夠,沒辦法解決這個問題
賽后看了官方題解后也是思考了好久才勉強想明白,這里就大體說一下題解的意思吧
因為動態維護炸彈比較困難,所以我們不妨將問題轉換為判斷答案是否合理,不難看出,隨著炸彈數量的增加,輸出的答案也會保持著非嚴格遞減的趨勢,所以我們從最大的答案開始不斷遞減,每次判斷是否合理即可
轉換思路后,接下來的任務就是對于一個答案 x ,我們如何判斷他的合理性,如果答案 x 滿足條件,也就是所有炸彈都炸掉了極大值后,x 成為了最后集合中的最大值,這也就必須滿足所有大于 x 的值都被炸彈炸掉了,因為炸彈影響的范圍是 [ 1 , q[ i ] ] ,也就是會影響一個前綴,那么:
如果滿足上述條件的話,就說明 > x 的所有數都會被炸彈炸掉,那么答案就肯定不可能是 x + 1 及以上了,只可能是 x 及以下
此時我們可以用線段樹維護一下每個節點 右側炸彈的個數 - 右側大于 x 的數的個數 ,顯然對于每個節點而言,如果這個值大于等于 0 的話,那么 x + 1 及以上的答案是肯定不可能的,因為全都被炸彈炸沒了,我們就可以用一個 while 維護符合條件的答案了,又因為我們需要所有的答案都大于等于 0 時才滿足條件,所以我們只需要維護一下區間最小值就好了,最小值如果大于等于 0 的話,那么就說明所有節點都滿足這個條件了
明白了思路后代碼寫起來就簡單多了,線段樹維護最小值+區間更新
代碼:
#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=3e5+100;int pos[N];struct Node {int l,r,mmin,lazy; }tree[N<<2];void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;tree[k].lazy=tree[k].mmin=0;if(l==r)return;int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r); }void pushdown(int k) {if(tree[k].lazy){int lz=tree[k].lazy;tree[k].lazy=0;tree[k<<1].mmin+=lz;tree[k<<1].lazy+=lz;tree[k<<1|1].mmin+=lz;tree[k<<1|1].lazy+=lz;} }void update(int k,int l,int r,int val) {if(tree[k].l>r||tree[k].r<l)return;if(tree[k].l>=l&&tree[k].r<=r){tree[k].mmin+=val;tree[k].lazy+=val;return;}pushdown(k);update(k<<1,l,r,val);update(k<<1|1,l,r,val);tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin); }int main() { #ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n;scanf("%d",&n);build(1,1,n);for(int i=1;i<=n;i++){int num;scanf("%d",&num);pos[num]=i;}int ans=n+1;for(int i=1;i<=n;i++){int q;scanf("%d",&q);while(tree[1].mmin>=0){ans--;update(1,1,pos[ans],-1);}printf("%d ",ans);update(1,1,q,1);}return 0; }?
總結
以上是生活随笔為你收集整理的CodeForces - 1326E Bombs(线段树+思维)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1325D E
- 下一篇: CodeForces - 1326D2