牛客xiao白月赛39 D(线段树维护区间)

简介: 牛客xiao白月赛39 D(线段树维护区间)


我没有打这个比赛,但是队友让我做了这个题(确实是好题),这次做的这个题目让我的线段树的理解获得了极大的提升,以往我的思维想的是:

pushup维护递归到子树后子树传递给父亲的信息。

pushdown维护父亲将要对子树的影响的信息。

回到这个题目:

通过分析题意结合唯一分解定理易知:

1.如果x==0 修改后的A[i]=ai,等于本身,即修改后原先是质数,那么修改后仍然是质数,原先不是质数,修改后仍不是质数。

2.如果x>1, 修改后的A[i]=p*ai(p>=1)。

1.如果p>1 那么ai修改后一定为合数。

2.如果p=1,那么ai修改后不变,他仍然是之前的数(不是质数或是质数)。

3 如果x=1,修改后的A[i]=i*ai,如果ai不为1,那么一定变合数;如果ai为1,A[i]变合数还是质数和i有关,i为质数即A[i]为质数,反之合数

在此,所有的情况就分析完了,接下来分析怎么样实现代码和改使用什么数据结构维护这些查询

暴力模拟,暴力啊!暴力出奇迹,看到 n m是1e5的级别这时候如果想暴力就没有写下去的必要了!

这时候问自己,什么能够维护区间?什么能在 mongn时间复杂度时间内优雅跑出答案?,答案呼之欲出!!!线段树

再想想实现方法

1.我们要的不是这个a[i]这个数的值,这个数只用一个用,他是否为质数,或者不是,我们要的是质数的总和,那么是质数标记1就行了,不是质数标记成0?,还不够!

2.本题有某个点质数和合数一直不变的情况,即a[1]的情况,a[i]无论x为什么a[i]都不会变,因为i==1;本题有非质数转化为合数的情况,如上文所提,i!=1&&a[i]==1时,a[i]变成质数和合数取决于i的是质数还是合数,而且他变了这一次后,便失去的这个特殊性

3.所以我们还要想办法将非质数转变成质数,这个==懒标记lz用的十分精髓,而且我从来没做过子树向父亲传递懒标记的题目,这个题目的懒标记用的十分6:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
struct node {
  int l;
  int r;
  int sum;// 1 质数 0 合数
  int lz; //1 质数  0 合数  2 是非质数(为1)但是可能变质数
} tr[N << 2];
int l, r, x, op;
int n, m;
bool f[N * 3];
int a[N];
void init() {//埃式筛
  f[1] = true;
  for (int i = 2; i <= 5e5 + 10; i++) {
    for (int j = i * 2; j <= 5e5 + 10; j += i) {
      f[j] = true;
    }
  }
}
void pushup(int u) {//向父亲传递影响
  if (tr[u << 1].lz == 0 && tr[u << 1 | 1].lz == 0) tr[u].lz = 0;//如果左区间和右区间都为合数,这个父亲区间再也不会有质数了,打一个标签 
  else tr[u].lz = 2;//这个区间可能有1变成质数的情况,要向下递归看
  tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;//这个区间的质数和=左树区间质数和+右树区间质数和
}
void build(int u, int l, int r) {//递归建树
  tr[u].l = l;
  tr[u].r = r;
  if (l == r) {
    //Tr[u].lz=is[a[l]];
    if (a[l] == 1 && l != 1)  tr[u].lz = 2;//如果a[i]=1,而且i!=1,那么它保留了变成质数的可能
    else if (!f[a[l]])  tr[u].lz = 1; //如果为质数 标记1
    else        tr[u].lz = 0;//合数标记 0
    if (tr[u].lz == 1)  tr[u].sum = 1; //0现在是质数  1不是质数.
    else      tr[u].sum = 0;
    return;
  }
  int mid = l + r >> 1;
  build(u << 1, l, mid);
  build(u << 1 | 1, mid + 1, r);
  pushup(u);
}
void update(int u, int l, int r, int k) {
  if (tr[u].lz == 0) return;//如果这个区间没有质数了,直接返回
  if (tr[u].l >= l && tr[u].r <= r) {
    if (tr[u].l == tr[u].r) {
      if (k > 1) { //所有质数变合数,合数还是合数,除a[1]的情况
        if (tr[u].l == 1 && tr[u].lz == 1) { a[1]是质数,那么它永远为质数,是合数则永远为合数
          tr[u].sum = 1;
          tr[u].lz = 1;
        } else {//其他质数全变合数
          tr[u].sum = 0;
          tr[u].lz = 0;
        }
      } else { // 质变和  为一的数可能会变质数
        if (a[tr[u].l] == 1 || tr[u].l == 1) {  //a[i]=1的情况,可能变质数
          a[tr[u].l] *= tr[u].l;
          if (!f[a[tr[u].l]]) tr[u].sum = 1, tr[u].lz = 1;
          else      tr[u].sum = 0, tr[u].lz = 0;
        } else {
          //其他质数全变合数
          if (tr[u].lz == 1)  tr[u].sum = 0, tr[u].lz = 0;
        }
      }
    }
     return;
  }
  int mid = tr[u].l + tr[u].r >> 1;
  if (l <= mid) update(u << 1, l, r, k);
  if (r > mid) update(u << 1 | 1, l, r, k);
  pushup(u);
}
int query(int u, int l, int r) {
  if (tr[u].l >= l && tr[u].r <= r) {
    return tr[u].sum;
  }
  int mid = tr[u].l + tr[u].r >> 1;
  int s = 0;
  if (l <= mid) s += query(u << 1, l, r);
  if (r > mid) s += query(u << 1 | 1, l, r);
  return s;
}
int main() {
  init();
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
  build(1, 1, n);
  while (m--) {
    scanf("%d", &op);
    if (op == 1) {
      scanf("%d%d%d", &l, &r, &x);
      if (x != 0) update(1, l, r, x);//x=0,更新等于没有更新
      cout << query(1, l, r) << "\n";
    } else {
      scanf("%d%d", &l, &r);
      cout << query(1, l, r) << "\n";
    }
  }
}

完结撒花

目录
相关文章
|
存储 Prometheus 监控
【监控利器Prometheus】——Prometheus+Grafana监控服务器资源
在Prometheus的架构设计中,Prometheus Server并不直接服务监控特定的目标,其主要任务负责数据的收集,存储并且对外提供数据查询支持。因此为了能够能够监控到某些东西,如主机的CPU使用率,我们需要使用到Exporter。Prometheus周期性的从Exporter暴露的HTTP服务地址(通常是/metrics)拉取监控样本数据。
【监控利器Prometheus】——Prometheus+Grafana监控服务器资源
|
10月前
|
数据采集 JavaScript 搜索推荐
服务器端渲染(SSR)(Nuxt+Next.js)
服务器端渲染(SSR)技术在服务器上生成页面HTML,提升首屏加载速度和SEO效果。Nuxt.js和Next.js分别是基于Vue.js和React.js的流行SSR框架。Nuxt.js提供自动化路由管理、页面级数据获取和布局系统,支持SSR和静态站点生成。Next.js支持SSR、静态生成和文件系统路由,通过`getServerSideProps`和`getStaticProps`实现数据获取。SSR的优点包括首屏加载快、SEO友好和适合复杂页面,但也会增加服务器压力、开发限制和调试难度。选择框架时,可根据项目需求和技术栈决定使用Nuxt.js或Next.js。
|
Python
Python软件包及环境管理器conda实战篇
详细介绍了如何使用conda进行Python软件包管理及环境管理,包括查看、安装、卸载软件包,切换源,管理不同版本的Python环境,以及解决使用过程中可能遇到的错误。
464 2
Python软件包及环境管理器conda实战篇
|
11月前
|
缓存 监控 前端开发
怎样提升 Flutter 应用的性能
【10月更文挑战第4天】
|
11月前
|
监控 Java 对象存储
监控与追踪:如何利用Spring Cloud Sleuth和Netflix OSS工具进行微服务调试
监控与追踪:如何利用Spring Cloud Sleuth和Netflix OSS工具进行微服务调试
171 1
|
编译器 C# Windows
C#基础:手动编译一个.cs源代码文件并生成.exe可执行文件
通过上述步骤,应该能够高效准确地编译C#源代码并生成相应的可执行文件。此外,这一过程强调了对命令行编译器的理解,这在调试和自动化编译流程中是非常重要的。
942 2
|
开发框架 监控 JavaScript
基于SqlSugar的开发框架循序渐进介绍(11)-- 使用TypeScript和Vue3的Setup语法糖编写页面和组件的总结
基于SqlSugar的开发框架循序渐进介绍(11)-- 使用TypeScript和Vue3的Setup语法糖编写页面和组件的总结
|
JavaScript 前端开发 Linux
|
JavaScript 前端开发
必知的技术知识:esm前端模块化
必知的技术知识:esm前端模块化
263 0
|
XML Java Android开发
Android实时显示时间日期(极简)
Android实时显示时间日期(极简)
312 0