牛客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";
    }
  }
}

完结撒花

目录
相关文章
excel中同一单元格内容分隔到不同的单元格
excel中同一单元格内容分隔到不同的单元格
excel中同一单元格内容分隔到不同的单元格
|
数据采集 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。
|
编译器 C# Windows
C#基础:手动编译一个.cs源代码文件并生成.exe可执行文件
通过上述步骤,应该能够高效准确地编译C#源代码并生成相应的可执行文件。此外,这一过程强调了对命令行编译器的理解,这在调试和自动化编译流程中是非常重要的。
1244 2
|
11月前
|
云安全 运维 监控
叮咚!您有一份六大必做安全操作清单,请查收
叮咚!您有一份六大必做安全操作清单,请查收
Mockito框架里面的@Mock注解原理
一文看懂@Mock注解的底层的底层原理:@Mock注解的底层其实就是用cglib
4396 0
|
关系型数据库 数据库 PostgreSQL
PostgreSQL 递归死循环案例及解法
背景 PostgreSQL 提供的递归语法是很棒的,例如可用来解决树形查询的问题,解决Oracle用户 connect by的语法兼容性。 请参考https://yq.aliyun.com/articles/54657 但是如果参与递归查询的数据集有问题,例如数据打结的问题。则会导致递
7374 0
|
JavaScript Java 测试技术
基于SpringBoot+Vue的电影播放平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的电影播放平台的详细设计和实现(源码+lw+部署文档+讲解等)
152 0
|
Linux Docker 容器
docker配置代理
docker配置代理
1806 0
|
移动开发 数据安全/隐私保护
H5实现隐形水印的一些思路
H5实现隐形水印的一些思路
886 0
H5实现隐形水印的一些思路