題目鏈接:點擊查看
題目大意:給出一個長度為 n 的數組 a 和計算貢獻的數組 sum,需要執行 m 次操作,每次操作分為下列兩種類型:
1 l r x:將區間 [ l , r ] 內的 a 用 x 覆蓋,即 i ∈[ l , r] , a[ i ] = x,且 sum[ i ] += abs( a[ i ] - x )2 l r:詢問區間 [ l , r ] 內的 sum 數組之和
題目分析:修改時直接將元素相同的區間統一處理即可,這里作為一個剪枝,可以讓時間復雜度均攤下來是 nlogn 的,寫好pushdown和pushup兩個函數的細節,剩下的碼就好了,需要注意的是,cover 只用上傳就好,沒必要下傳(因為下傳 cover 沒有意義)
稍微證明一下復雜度,假設對于某段區間內的元素相同的話我們將其“合并”為一個整體,那么對于每次修改來說,至多增加兩個整體,也就是說最壞的情況就是將一個整體從中間修改,然后分割成了三個整體
如此一來我們按照最壞的時間復雜度去計算修改的代價,也就是:
第一次將 n 個整體合并成一個整體:O( nlogn )后面的 n/2?次將一個整體每次增加兩個整體,每次修改的復雜度是 O( logn ),此時數組又變為了 n 個整體接下來再一次將 n 個整體合并成一個整體:O( nlogn )后面的 n/2 次再繼續每次增加兩個整體,每次復雜度是 O( logn )
如此一來不難看出,“合并” 操作累加起來的復雜度不會超過 2*nlogn 次,所以均攤下來的時間復雜度仍然是 O( nlogn ) 的,只不過多了點常數罷了
代碼:
?
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#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>
#include<cassert>
#include<bitset>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;struct Node
{int l,r;LL val,sum,len,lazy;bool cover;
}tree[N<<2];void pushup(int k)
{tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;if(tree[k<<1].cover&&tree[k<<1|1].cover&&tree[k<<1].val==tree[k<<1|1].val){tree[k].cover=true;tree[k].val=tree[k<<1].val;}elsetree[k].cover=false;
}void update(int k,LL val,LL add)
{tree[k].sum+=tree[k].len*add;tree[k].lazy+=add;tree[k].val=val;
}void pushdown(int k)
{if(tree[k].lazy){LL lz=tree[k].lazy;tree[k].lazy=0;update(k<<1,tree[k].val,lz);update(k<<1|1,tree[k].val,lz);}
}void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;tree[k].len=r-l+1;tree[k].sum=tree[k].val=tree[k].lazy=0;if(l==r){tree[k].cover=true;tree[k].val=l;return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}void update(int k,int l,int r,LL val)
{if(tree[k].l>r||tree[k].r<l)return;if(tree[k].l>=l&&tree[k].r<=r&&tree[k].cover){update(k,val,llabs(tree[k].val-val));return;}pushdown(k);update(k<<1,l,r,val);update(k<<1|1,l,r,val);pushup(k);
}LL query(int k,int l,int r)
{if(tree[k].l>r||tree[k].r<l)return 0;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].sum;pushdown(k);return query(k<<1,l,r)+query(k<<1|1,l,r);
}int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);int n,m;scanf("%d%d",&n,&m);build(1,1,n);while(m--){int op;scanf("%d",&op);if(op==1){int l,r,x;scanf("%d%d%d",&l,&r,&x);update(1,l,r,x);}else{int l,r;scanf("%d%d",&l,&r);printf("%lld\n",query(1,l,r));}}return 0;
}
?
總結
以上是生活随笔為你收集整理的CodeForces - 444C DZY Loves Colors(线段树+剪枝)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。