華麗的序列題解
阿新 • • 發佈:2021-08-04
華麗的序列題解
題目描述 給定一個長度為 nn 的序列,序列上第 ii 個數為 aiai,有 QQ 次操作: 1.給定l,r,x,ai修改為min(ai,x),i∈[l,r]給定l,r,x,ai修改為min(ai,x),i∈[l,r] 2.給定l,r,詢問max(ai),i∈[l,r]給定l,r,詢問max(ai),i∈[l,r] 3.給定l,r,詢問[l,r]之間所有ai的和給定l,r,詢問[l,r]之間所有ai的和 輸入格式 每次輸入有多組資料,首先第一行一個整數TT,表示測試的個數。 在每次測試中都另起一行有兩個整數n,mn,m。 接下來一行有nn個整數表示該序列。 接下來mm行表示所有操作,每次操作的第一個數typetype表示操作的型別,題目描述中的操作按順序分別對應type=0,1,2type=0,1,2。 剩下的見題目描述即可。 輸出格式 對每次詢問一行一個整數表示答案。 樣例 輸入樣例 1 5 5 1 2 3 4 5 1 1 5 2 1 5 0 3 5 3 1 1 5 2 1 5 輸出樣例 5 15 3 12 樣例解釋 資料範圍與提示 n,Q≤106,T≤10n,Q≤106,T≤10 保證所有的aiai不超過231231。
沒連結,放題面好了。
這道題是一類線段樹的例題,好像有個專門的名字忘了基本上都是修改大於k的或者小於k的,思路都一樣廢話或者拐彎抹角的,這道題還是比較裸的。
題解
首先
對於操作3用線段樹維護一個區間和,然後就是要在操作1和操作2的過程中想辦法保證線段樹合法。
我們先來考慮操作2,我們只需要線上段樹中維護一個最大值,在進行修改時區間修改的過程中維護區間和即可具體為:
t[id].sum=(t[id].r-t[id].l+1)*t[id].maxx;
t[id].lazy=t[id].maxx;
接著是本題唯一的難點操作1,其實略微的處理一下即可,我們在維護最大值的同時維護一個次大值和最大值的數量,噹噹前詢問的區間被包含並且a小於最大值但是大於次大值時修改最大值 ,並且注意一個技巧無論何時當a大於當前區間的最大值跳出即可,因為區間中的元素一個也不會被修改。記得開longlong
標程
#include<bits/stdc++.h> using namespace std; const int MN=1e6+100; const int inf=0x3f3f3f3f; typedef long long ll; int T,n,m; inline void write(ll x){ if(x<0)putchar('-'),x=~x+1; if(x>9)write(x/10);putchar(x%10+'0'); } struct node{ int l,r; ll maxx,smx,cmx,sum; }t[MN<<2]; inline void pushup(int id){ int l(id<<1),r(id<<1|1); if(t[l].maxx>t[r].maxx){ t[id].maxx=t[l].maxx; t[id].cmx=t[l].cmx; t[id].smx=max(t[l].smx,t[r].maxx); } else if(t[r].maxx>t[l].maxx){ t[id].maxx=t[r].maxx; t[id].cmx=t[r].cmx; t[id].smx=max(t[r].smx,t[l].maxx); } else{ t[id].maxx=t[l].maxx; t[id].cmx=t[l].cmx+t[r].cmx; t[id].smx=max(t[l].smx,t[r].smx); } t[id].sum=t[l].sum+t[r].sum; } inline void puttag(int id,ll v){ if(t[id].maxx<=v)return; t[id].sum-=t[id].cmx*(t[id].maxx-v); t[id].maxx=v; } inline void pushdown(int id){ puttag(id<<1,t[id].maxx),puttag(id<<1|1,t[id].maxx); } inline void build(int id,int l,int r){ t[id].l=l,t[id].r=r; if(l==r){ ll x; scanf("%lld",&x); t[id].maxx=t[id].sum=x; t[id].cmx=1; t[id].smx=-1; return; } int mid(l+r>>1); build(id<<1,l,mid),build(id<<1|1,mid+1,r); pushup(id); } inline void change(int id,int l,int r,ll k){ if(t[id].maxx<=k)return; if(t[id].l>=l&&t[id].r<=r&&t[id].smx<k){ puttag(id,k); return; } int mid(t[id].l+t[id].r>>1); pushdown(id); if(l<=mid)change(id<<1,l,r,k); if(r>=mid+1)change(id<<1|1,l,r,k); pushup(id); } inline ll get_sum(int id,int l,int r){ if(t[id].l>=l&&t[id].r<=r){ return t[id].sum; } int mid(t[id].l+t[id].r>>1); ll ans=0; pushdown(id); if(l<=mid)ans+=get_sum(id<<1,l,r); if(r>=mid+1)ans+=get_sum(id<<1|1,l,r); return ans; } inline ll get_max(int id,int l,int r){ if(t[id].l>=l&&t[id].r<=r){ return t[id].maxx; } int mid(t[id].l+t[id].r>>1); ll ans=-inf; pushdown(id); if(l<=mid)ans=max(ans,get_max(id<<1,l,r)); if(r>=mid+1)ans=max(get_max(id<<1|1,l,r),ans); return ans; } signed main(){ //freopen("gorgeoussequence.in","r",stdin); //freopen("gorgeoussequence.out","w",stdout); scanf("%d",&T); while(T--){ memset(t,0,sizeof(t)); scanf("%d%d",&n,&m); build(1,1,n); int type,l,r; ll x; for(int i=1;i<=m;++i){ scanf("%d",&type); if(type==0){ scanf("%d%d%lld",&l,&r,&x); change(1,l,r,x); } else if(type==1){ scanf("%d%d",&l,&r); write(get_max(1,l,r)); putchar('\n'); } else{ scanf("%d%d",&l,&r); write(get_sum(1,l,r)); putchar('\n'); } } } return 0; }