牛客小白月賽30 B.最好的寶石 (線段樹)
阿新 • • 發佈:2020-12-07
- 題意:RT.
- 題解:很明顯的線段樹維護區間最大值操作,但是我們同時還要維護最大值的個數,我們在build或者modify操作完子樹然後push_up的時候,我們先從兩個兒子取max更新父節點的最大值,然後再判斷父節點的最大值是否和兩個兒子相等,這樣我們就成功的維護了區間最大值的個數.剩下的就是線段樹的板子了.
- 程式碼:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n,m; int w[N]; struct Node{ int l,r; int v; int cnt; }tr[N<<2]; void push_up(int u){ tr[u].v=max(tr[u<<1].v,tr[u<<1|1].v); tr[u].cnt=0; if(tr[u].v==tr[u<<1].v) tr[u].cnt+=tr[u<<1].cnt; if(tr[u].v==tr[u<<1|1].v) tr[u].cnt+=tr[u<<1|1].cnt; } void build(int u,int l,int r){ tr[u].l=l,tr[u].r=r,tr[u].cnt=0; if(l==r){ tr[u].v=w[r]; tr[u].cnt=1; return; } int mid=(l+r)>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); push_up(u); } void modify(int u,int x,int v){ if(tr[u].l==x && tr[u].r==x){ tr[u].v=v; } else{ int mid=(tr[u].l+tr[u].r)>>1; if(x<=mid) modify(u<<1,x,v); else modify(u<<1|1,x,v); push_up(u); } } Node query(int u,int l,int r){ if(tr[u].l>=l && tr[u].r<=r) return tr[u]; else{ int mid=(tr[u].l+tr[u].r)>>1; if(r<=mid) return query(u<<1,l,r); else if(l>mid) return query(u<<1|1,l,r); else{ Node left=query(u<<1,l,r); Node right=query(u<<1|1,l,r); Node res; res.v=max(left.v,right.v); res.cnt=0; if(res.v==left.v) res.cnt+=left.cnt; if(res.v==right.v) res.cnt+=right.cnt; return res; } } } int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n>>m; rep(i,1,n) cin>>w[i]; build(1,1,n); while(m--){ string op; cin>>op; if(op=="Change"){ int x,y; cin>>x>>y; modify(1,x,y); } else{ int l,r; cin>>l>>r; Node res=query(1,l,r); cout<<res.v<<' '<<res.cnt<<'\n'; } } return 0; }