- 题目大意:给定序列,每次操作可以单点修改以及询问每个区间内严格次大值出现次数。
- 此类区间合并的线段树之前也做过,但是都没有一个固定的写法,导致调了很久都过不了,感觉上是写丑了。对于一个节点要维护多个信息,我们可以用结构体来实现,并且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;
}
标签:num1,num2,res,tr,long,Second,ls,此题,Largest
From: https://www.cnblogs.com/lwiwi/p/18687783