首页 > 其他分享 >III.追想 题解

III.追想 题解

时间:2023-05-22 12:25:24浏览次数:61  
标签:log 追想 int 题解 rc 操作 III mx se

原题链接

我第一次出的一道比较正经的菜题,欢迎大家来切哦。
感谢魔法少女老干妈 GM_Joanna_ 的支持

对于操作 1,3:

注意到 1e9 的数据至多 5 此操作就能把一个位置变为 0,这个次数可视为常数。
考虑每个位置暴力改,也只会递归 \(5\times n\log n\) 次。
对于 3 操作,考虑最坏的情况,每次把一些数还原成 1e9。
注意到 3 操作后一些数是相同的,那么对于相同的数,就可以直接进行区间 1 操作。
线段树上区间操作复杂度 \(O(\log n)\)。
总复杂度 \(O(n\log ^2 n)\)。

对于操作 2:

吉司机线段树维护即可。
简略提一下吉司机线段树。

记当前区间最大值为 \(mx\),次大值为 \(se\)。现在有如下三种情况:

  1. \(mx\leq v\),直接返回。
  2. \(se<v \leq mx\),只修改当前区间最大值,可以打标记维护。
  3. \(v \leq se\),暴力递归修改,若在叶子节点,直接修改最大值。

证一下时间复杂度

  • 递归次数与值域(不同数值个数)相关,因为相同的数第二种情况可以直接进行区间操作。
  • 每次递归条件是 \(v \leq se < mx\),则至少会令 \(se=mx=v\),显然值域至少 \(-1\)。
  • 不论区间修改还是单点修改,最多只会令值域 \(+1\)。
  • 线段树 \(\log n\) 层,每层值域 \(n\),区间修改+单点修改次数 \(n\log n\) 次,故总复杂度 \(O(n\log^2 n)\)。

一些细节:

  1. 由于要打区间覆盖和修改最大值的两种标记,要注意下传标记的顺序。
  2. \(\log\) 函数自己手写,用换底公式可能有精度误差。
  3. 暴力进行 \(\log\) 操作到叶子节点时,注意把标记给清空(这鬼地方我调半天)。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N=5e5+5;
int n,m,a[N];

struct SegmentTree{
    int mx[N<<2],se[N<<2],c[N<<2],tag[N<<2],tag_mx[N<<2];
    ll sum[N<<2];
    #define lc k<<1
    #define rc k<<1|1
    #define mid ((l+r)>>1)
    inline int max(int x,int y) {return x>y?x:y;}
    inline int log(int x,int k)
    {
        if(x==0) return 0;
        ll res=0,t=1;
        while(t<=x) res++,t*=k;
        return res-1;
    }

    inline void pushup(int k)
    {
        sum[k]=sum[lc]+sum[rc];
        if(mx[lc]==mx[rc])
        {
            mx[k]=mx[lc];
            se[k]=max(se[lc],se[rc]);
            c[k]=c[lc]+c[rc];
        }
        else if(mx[lc]>mx[rc])
        {
            mx[k]=mx[lc];
            se[k]=max(se[lc],mx[rc]);
            c[k]=c[lc];
        }
        else
        {
            mx[k]=mx[rc];
            se[k]=max(mx[lc],se[rc]);
            c[k]=c[rc];
        }
    }

    inline void pushtag(int k,int l,int r,int v)
    {
        tag[k]=mx[k]=v;
        c[k]=r-l+1;
        sum[k]=1ll*(r-l+1)*v;
        se[k]=-1;
    }

    inline void push_mx(int k,int l,int r,int v)
    {
        if(~tag[k])
        {
            if(tag[k]<=v) return;
            tag[k]=mx[k]=v;
            sum[k]=1ll*(r-l+1)*v;
        }
        else
        {
            if(mx[k]<=v) return;
            sum[k]-=1ll*c[k]*(mx[k]-v);
            mx[k]=tag_mx[k]=v;
        }
    }

    inline void pushdown(int k,int l,int r)
    {
        if(~tag[k])
        {
            pushtag(lc,l,mid,tag[k]);
            pushtag(rc,mid+1,r,tag[k]);
            tag[k]=-1,tag_mx[k]=-1;
        }
        if(~tag_mx[k])
        {
            push_mx(lc,l,mid,tag_mx[k]);
            push_mx(rc,mid+1,r,tag_mx[k]);
            tag_mx[k]=-1;
        }
        
    }

    void build(int k=1,int l=1,int r=n)
    {
        tag[k]=tag_mx[k]=-1;
        if(l==r) return sum[k]=mx[k]=a[l],c[k]=1,se[k]=-1,void();
        build(lc,l,mid),build(rc,mid+1,r);
        pushup(k);
    }

    void upd_log(int x,int y,int v,int k=1,int l=1,int r=n)
    {
        if(mx[k]<=0) return;
        if(l>=x&&r<=y&&~tag[k]) return pushtag(k,l,r,log(tag[k],v)),void();
        if(l==r)
        {
            mx[k]=log(mx[k],v);
            sum[k]=mx[k];
            tag[k]=tag_mx[k]=-1;
            return;
        }
        pushdown(k,l,r);
        if(x<=mid) upd_log(x,y,v,lc,l,mid);
        if(mid<y) upd_log(x,y,v,rc,mid+1,r);
        pushup(k);
    }

    void upd_min(int x,int y,int v,int k=1,int l=1,int r=n)
    {
        if(mx[k]<=v) return;
        if(l>=x&&r<=y&&se[k]<v) return push_mx(k,l,r,v);
        pushdown(k,l,r);
        if(x<=mid) upd_min(x,y,v,lc,l,mid);
        if(mid<y) upd_min(x,y,v,rc,mid+1,r);
        pushup(k);
    }

    void upd_cov(int x,int y,int v,int k=1,int l=1,int r=n)
    {
        if(l>=x&&r<=y) return pushtag(k,l,r,v);
        pushdown(k,l,r);
        if(x<=mid) upd_cov(x,y,v,lc,l,mid);
        if(mid<y) upd_cov(x,y,v,rc,mid+1,r);
        pushup(k);
    }

    ll query(int x,int y,int k=1,int l=1,int r=n)
    {
        if(l>=x&&r<=y) return sum[k];
        pushdown(k,l,r);
        ll res=0;
        if(x<=mid) res=query(x,y,lc,l,mid);
        if(mid<y) res+=query(x,y,rc,mid+1,r);
        return res;
    }
}T;

inline int rd()
{
    int x=0;char c=getchar();
    for(;!isdigit(c);c=getchar());
    for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
    return x;
}

int main()
{
    n=rd(),m=rd();
    for(int i=1;i<=n;i++) a[i]=rd();
    T.build();
    while(m--)
    {
        int op=rd(),l=rd(),r=rd(),x;
        if(op!=4) x=rd();
        if(op==1) T.upd_log(l,r,x);
        else if(op==2) T.upd_min(l,r,x);
        else if(op==3) T.upd_cov(l,r,x);
        else printf("%lld\n",T.query(l,r));
    }
}

标签:log,追想,int,题解,rc,操作,III,mx,se
From: https://www.cnblogs.com/spider-oyster/p/17420268.html

相关文章

  • Nas Docker 安装个人记账web项目:firefly_iii &beancount-gs
    NasDocker安装个人记账web项目:firefly_iii&beancount-gs1.经过搜索以及GPT的询问,通过预览界面感觉firefly_iii官方示例demo:https://demo.firefly-iii.org/官方安装文档:https://docs.firefly-iii.org/firefly-iii/installation/docker/本人采用的是群晖Nasdocker安装:这个......
  • 【题解】Atcoder ABC302 F,G,Ex
    完全不会G和Ex,这些套路还是要积累一下的。F.MergeSet题目描述:给定\(n\)个集合,每次可以合并两个有交的集合,问最少多少次合并可以让\(1\)和\(m\)位于同一个集合中。题目分析:一开始将题读成了将\([1,m]\)位于同一个集合中,然后就感觉这个题相当不可做。因为集合的元......
  • NOIP2018普及组试题题解
    1.标题统计原题:https://www.luogu.com.cn/problem/P5015#include<bits/stdc++.h>#definelllonglongusingnamespacestd;strings;intans=0;intmain(){ getline(cin,s);intlen=s.length(); for(inti=0;i<len;i++){ if(s[i]>='0'&&......
  • #球钟算法题解以及代码完成
    球钟问题描述:球钟是一个利用球的移动来记录时间的简单装置。它有三个可以容纳若干个球的指示器:分钟指示器,五分钟指示器,小时指示器。若分钟指示器中有2个球,5分钟指示器中有6个球,小时指示器中有5个球,则时间为5:32。       工作原理:每过一分钟,球钟就会从球队列的队首......
  • abc302 题解
    打的还行,加的分不多。A直接除完上取整即可。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;constintN=1e5+5,INF=0x3f3f3f3f;constLLmod=1e9+7;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr); LLa,b; ci......
  • 【CF1833C】题解
    本文章同步发表于洛谷思路首先,先明确一点:同奇偶的两个数相减,等于偶数。奇偶性不同的两个数相减,等于奇数。接下来,我们要确定要都变成奇数还是偶数。偶数?如果是偶数,由于要同奇偶的两个数相减,结果才等于偶数。又因为改变后的每个数都要\(\gt0\),所以,最小的奇数没有可以与其......
  • 【CF1833D】题解
    本文章同步发表于洛谷思路这是一道水题,但细节很多......首先,要求字典序最大,显然就想到了让最大的数字在第一位。于是就进一步得出了应该让最大数字在翻转区间的后一位,初步得出了以下思路:找到最大的数(\(n\))所在位置\(r\),将\(r-1\);贪心的寻找\(r-1\)以前第一个比\(p_1\)......
  • 【题解】CF193D Two Segments
    题意给定一个\(1\simN\)的排列,在这个排列中选出两段互不重叠的区间,求使选出的元素排序后构成公差为1的等差数列的方案数。选出的两段区间中元素构成的集合相同时视为同一种方案。\(1\leN\le3\times10^5\)。传送门分析如果考虑怎么优化枚举的两个区间的话,发现不太好搞(反正......
  • jre jdk更改目录后Java无法运行问题解决方案
    问题:在将Java文件(包含jdkjre)由C盘直接剪贴到D盘后,所有Java程序无法运行,且其Java图标不再显示。解决方案:首先更改环境变量。当我们单纯地将Java文件更改位置后,我们计算机的环境变量仍未改变,依旧是当时安装Java时的配置。步骤:控制面板—>系统和安全—>系统—>高级系统设置—>环境......
  • P5179 Fraction 题解
    题目描述给你四个正整数\(a,\,b,\,c,\,d\),求一个最简分数\(\frac{p}{q}\)满足\(\frac{a}{b}<\frac{p}{q}<\frac{c}{d}\)。若有多组解,输出\(q\)最小的一组,若仍有多组解,输出\(p\)最小的一组。前置知识:Stern-Brocot树首先引入分数逼近。这里的分数逼近是指用用一个......