題意:給定\(a[1...n]\),\(m\)次操作,0表示使\([l,r]\)中的值\(a[i]=min(a[i],x)\),其餘的1是查最值2是查區間和
本題是jls的2016**題,1 2套路不說
對於操作0,維護當前最值和嚴格次大最值,更新過程分三種情況
1.當前的最大值本來就比\(x\)小或相等,直接剪枝(全域性剪枝更優,道理不必多說)
2.當前最大值大於\(x\),次大值小於等於\(x\),那麼影響到的值只有最大值,打個tag維護
3.其它情況,暴力dfs
具體地,\(max\)值的改變影響了\(sum\)值,那我們需要維護的tag需要值為\(max\)的個數,此時\(sum\)只需做差相減
**證明這種操作下依然是\(o(logn)\)的
**改得比較多,略醜
細節要注意的地方也挺多的
#include#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)a)
#define println(a) printf("%lld\n",(ll)(a))
using namespace std;
const int maxn = 1e6+11;
const int nn = 1e5+11;
const int inf = 0x3f3f3f3f;
const double eps = 1e-7;
typedef long long ll;
const ll mod = 1e9+7;
ll read()
while(ch>='0'&&ch<='9')
return x*f;
}int a[maxn];
struct st
void pd(int o)
if(mx[rc]>mx[o])
lazy[o]=0;
// lazy[lc]=lazy[rc]=1;}}
void build(int o,int l,int r)
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pu(o);
}void update(int o,int l,int r,int l,int r,int v)
}pd(o);
int mid=l+r>>1;
if(l<=mid) update(lc,l,mid,l,r,v);
if(r>mid) update(rc,mid+1,r,l,r,v);
pu(o);
}ll querymax(int o,int l,int r,int l,int r)
ll querysum(int o,int l,int r,int l,int r)
}st;
int main()else if(op==1)else}}
return 0;
}
hdu 預處理 線段樹)
給n個數,m個詢問,問任意區間內與其它數互質的數有多少個 比如3個數1 2 4,詢問 1,3 那麼答案是1 千萬要記住,這樣的題目,如果你不轉變下,使勁往線段樹想 雖然轉變之後,也說要用到線段樹,但是維護的東西不同了 那麼會發現這樣的題目,區間與區間之間是無法傳遞資訊的,區間與區間是無法傳遞資訊的,...
hdu1541(線段樹的巧用)
線段樹的妙用,求乙個序列中的某個數字的前面有幾個比它小,樸素演算法是o n n 線段樹是o n logn 然後再變形下就是答案了 下面提供線段樹和樹狀陣列的解題 線段樹 include include include include include include include include i...
hdu 2795(線段樹的應用)
hdu 2795 1 思路 每個格仔的寬度都已經確定,所以一開始預設已知所有的格仔,建立線段樹,單點更新區間值 x位置的點,因為線段樹的結構類似二叉樹,所以可以將線段樹看做乙個類二叉樹,每次x先找左區間 先找下標小的區間 否則找右的區間,遞迴縮小區間,最終修改最接近x且最靠前的 點的值。2 注意 這...