首页 > 其他分享 >关于此题[ABC343F] Second Largest Query 线段树合并类问题的一些总结

关于此题[ABC343F] Second Largest Query 线段树合并类问题的一些总结

时间:2025-01-23 14:53:17浏览次数:1  
标签:num1 num2 res tr long Second ls 此题 Largest

传送门

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

相关文章

  • 关于此题[ABC389F] Rated Range 线段树二分的一些总结
    传送门题目大意依次给定\(n\)个区间,并给定\(q\)个数,每个数依次经过这些区间时若在区间中则加1,问最后每个数变成了多少。做法显然如果直接模拟的话时间复杂度肯定是会炸的。首先我们注意到这道题是可以离线处理的,并且对于所有询问的数,我们如果先对他们排好序,在每个数都......
  • 关于此题CF2061E_Kevin and And的一些总结
    传送门题目大意:给定\(n\)个数\(a[1...n]\)和\(m\)个数\(b[1...m]\),并且给定整数k,求让任意\(i,j\)使\(a[i]&b[j]\)来替代\(a[i]\)后这\(n\)个数总和最小。首先我们看到题目给的m范围非常小,最大只有10,然后又问我们k次操作之后总和的最小值,第一反应是不是可以直接先求出每个\(a[i]......
  • H1. Maximize the Largest Component (Easy Version)
    题目链接:Problem-H1-Codeforces题目大意:给一个由‘.'与’#‘的字符组合成的二维矩阵,现在又有一种操作可以使每一列或每一行全部变成’#‘,然后求这个二维矩阵里的由’#‘组合成的最大连通块,求出该最大连通块的大小。输入的第一行包含一个整数 tt(1≤t≤1e4 )-测试用......
  • 关于此题[ABC350E] Toward 0和[ABC188F] +1-1x2记忆化搜索的一些总结
    传送门1传送门2这两道题都有个特性,那就是数据范围到了\(10^{18}\),这会让我们想用记忆化搜索或者期望DP的想法望而却退但是实际上我们可以用map。有人会说,用map那时间上貌似也过不去啊!但是我们发现这两道题当中,我们可以进行的操作都有除法操作,这就有点像势能线段树,时间复杂度实......
  • 关于此题[ABC 387]C - Snake Numbers 数位DP的一些总结
    传送门这道题要求我们求[l,r]范围内所有的“蛇数”,即这个数的第一位严格大于它的其他位的数。看到数据范围并且发现答案区间可加减性联想到数位DP。其实有点类似模板题,与经典的数位DP题类似的,我们需要判断前导0,需要判断当前枚举的数是否是贴着所给的数,在此题中如果想要记忆化的......
  • 关于此题[ABC367E] Permute K times倍增思想的一些总结
    传送门第一次接触到倍增思想是用来求lca时,为了避免一层一层往上爬浪费时间复杂度。再后来就是区间DP中一小类问题或者是部分图上问题可以用倍增来优化。那么这道题其实可以看作图上问题来使用倍增优化。看到这道题的数据范围,K达到了\(10^{18}\)量级,这让我们不得不思考log级别往......
  • 关于此题[ABC367F] Rearrange Query随机化哈希的一些总结
    传送门这道题要求我们对于非常多的询问回答[l,r]、[L,R]这样两个区间内A、B数组中各个数的出现次数是否相同。看到这道题似乎想到了刚开始学编程的时候就想过的一个问题(bushi,那就是我能不能直接用,例如说这段区间和是否相同,或者说这段区间乘积之类的是否相同来判断这个区间各个数......
  • 关于此题CF[Hello 2025] 2057C - Trip to the Olympiad的一些总结
    传送门题目大意:给定两个数l,r,试求l~r中选三个数a,b,c,使得\((axorb)+(bxorc)+(axorc)\)的值最大。有关此类异或最大的题目,首先想到的是确定最高位,因为假如说异或后二进制下k位置为1,那么此时答案就已经比k位置不为1,而k以后的位置都是1的情况要大了。而观察l,r这两个数,我......
  • 关于此题[ABC382E] Expansion Packs 概率DP的一些总结
    传送门首先看到这道题,我们发现想要求收集K个卡牌的期望开包数,必须要先求出每个包开出0~n张卡各自的概率,于是预示着这道题将要进行两次概率DP。首先我们求每个包开出0~n张卡各自的概率。这个很好求,我们假设f[i][j]表示前\(i\)张卡中开出\(j\)张卡的概率,那么显然有:\(f[i][j]=p[......
  • 关于此题E - Maximize XOR(Atcoder ABC 386)搜索技巧的一些总结
    传送门题目要求n个数中选k个数异或起来最大,我们想到字典树中最大异或和这一经典问题,但是很明显字典树只能解决任选两个数的最大异或,而此题是任选k个,那我们走投无路只能考虑爆搜。首先可以很容易写出一个暴力的搜索:voiddfs1(longlongpos,longlongsum,longlongkk){i......