传送门
- 题目大意:给定序列,每次操作可以单点修改以及询问每个区间内严格次大值出现次数。
- 此类区间合并的线段树之前也做过,但是都没有一个固定的写法,导致调了很久都过不了,感觉上是写丑了。对于一个节点要维护多个信息,我们可以用结构体来实现,并且pushup操作,即左右儿子两个区间合并操作,可以直接返回node类型到当前节点,这样的好处是询问操作也直接用node作为返回值可以一个query就得到答案,不然还得一个query找次大值,再来个query找次大值出现次数。
- 这里的合并操作可以分类讨论,也可以用set完成,我这里用的是set,写起来更加方便且不容易出错。
#include<bits/stdc++.h>using namespace std;long long t;
const long long N = 2e5 + 10;
long long n,m;
long long a[N];
struct node {long long max1,max2,num1,num2;
}tr[4*N];node up(node ls,node rs) {node res;res.max1 = res.max2 = res.num1 = res.num2 = 0;set<long long,greater<long long> > tq;tq.insert(ls.max1);tq.insert(ls.max2);tq.insert(rs.max1);tq.insert(rs.max2);set<long long>::iterator it = tq.begin();res.max1 = *it;if(ls.max1 == *it) res.num1 += ls.num1;if(ls.max2 == *it) res.num1 += ls.num2;if(rs.max1 == *it) res.num1 += rs.num1;if(rs.max2 == *it) res.num1 += rs.num2;it++;if(*it != 0) {res.max2 = *it;if(ls.max1 == *it) res.num2 += ls.num1;if(ls.max2 == *it) res.num2 += ls.num2;if(rs.max1 == *it) res.num2 += rs.num1;if(rs.max2 == *it) res.num2 += rs.num2;}return res;
}void build(long long k,long long l,long long r) {if(l == r) {tr[k].max1 = a[l];tr[k].num1 = 1;return;}long long mid = (l + r) >> 1;build(k * 2,l,mid);build(k * 2 + 1,mid + 1,r);tr[k] = up(tr[k * 2],tr[k * 2 + 1]);
}void modify(long long k,long long l,long long r,long long pos,long long v) {if(l > pos || r < pos) return;if(l == r && l == pos) {tr[k].max1 = a[l] = v;tr[k].max2 = 0;tr[k].num1 = 1;tr[k].num2 = 0;return ;}long long mid = (l + r) >> 1;modify(k * 2,l,mid,pos,v);modify(k * 2 + 1,mid + 1,r,pos,v);tr[k] = up(tr[k * 2],tr[k * 2 + 1]);
}node query(long long k,long long l,long long r,long long x,long long y) {if(l > y || r < x) return {0,0,0,0};if(l >= x && r <= y) return tr[k];long long mid = (l + r) >> 1;if(y <= mid) return query(k * 2,l,mid,x,y);else if(x > mid) return query(k * 2 + 1,mid + 1,r,x,y);else return up(query(k * 2,l,mid,x,y),query(k * 2 + 1,mid + 1,r,x,y));
}void solve() {cin >> n >> m;for(long long i = 1;i <= n;i++) cin >> a[i];build(1,1,n);for(long long i = 1;i <= m;i++) {long long pd,x,y;cin >> pd >> x >> y;if(pd == 1)modify(1,1,n,x,y);else cout << query(1,1,n,x,y).num2 << '\n';}
}signed main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);t = 1;while(t--) solve();return 0;
}