题目大意:

一个数列 支持两种操作

1 把区间内的数变成他们自己的约数个数

2 求区间和

思路:

可以想到每个数最终都会变成2或1

然后我们可以线段树

修改的时候记录一下每段有没有全被修改成1或2 是的话就不修改了

不是就暴力修改 因为每个数被修改的次数很小

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 2139062143
#define ll long long
#define MAXN 1001000
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
int n,g[MAXN],cnt[MAXN],m;
struct data{ll sum,mx;}tr[MAXN<<];
inline void pshp(int k)
{
tr[k].sum=tr[k<<].sum+tr[k<<|].sum;
tr[k].mx=max(tr[k<<].mx,tr[k<<|].mx);
}
void build(int k,int l,int r)
{
if(l==r) {tr[k].sum=tr[k].mx=g[l];return ;}
int mid=(l+r)>>;
build(k<<,l,mid);build(k<<|,mid+,r);
pshp(k);
}
inline ll query(int k,int a,int b,int l,int r)
{
if(l==a&&r==b) return tr[k].sum;
int mid=(l+r)>>;
if(mid>=b) return query(k<<,a,b,l,mid);
else if(mid<a) return query(k<<|,a,b,mid+,r);
else return query(k<<,a,mid,l,mid)+query(k<<|,mid+,b,mid+,r);
}
inline void upd(int k,int a,int b,int l,int r)
{
if(tr[k].mx<=) return ;
if(l==r) {tr[k].sum=tr[k].mx=cnt[tr[k].mx];return ;}
int mid=(l+r)>>;
if(mid>=b) upd(k<<,a,b,l,mid);
else if(mid<a) upd(k<<|,a,b,mid+,r);
else {upd(k<<,a,mid,l,mid);upd(k<<|,mid+,b,mid+,r);}
pshp(k);
}
int main()
{
int a,b,c;
for(int i=;i<=MAXN;i++)
for(int j=i;j<=MAXN;j+=i) cnt[j]++;
n=read(),m=read();
for(int i=;i<=n;i++) g[i]=read();
build(,,n);
while(m--)
{
a=read(),b=read(),c=read();
if(a==) upd(,b,c,,n);
else printf("%I64d\n",query(,b,c,,n));
}
}

UPD:

bzoj 3211 区间开根号 思路同上

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 2139062143
#define ll long long
#define MAXN 100100
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
int n,g[MAXN],m;
struct data{ll sum,mx;}tr[MAXN<<];
inline void pshp(int k)
{
tr[k].sum=tr[k<<].sum+tr[k<<|].sum;
tr[k].mx=max(tr[k<<].mx,tr[k<<|].mx);
}
void build(int k,int l,int r)
{
if(l==r) {tr[k].sum=tr[k].mx=g[l];return ;}
int mid=(l+r)>>;
build(k<<,l,mid);build(k<<|,mid+,r);
pshp(k);
}
inline ll query(int k,int a,int b,int l,int r)
{
if(l==a&&r==b) return tr[k].sum;
int mid=(l+r)>>;
if(mid>=b) return query(k<<,a,b,l,mid);
else if(mid<a) return query(k<<|,a,b,mid+,r);
else return query(k<<,a,mid,l,mid)+query(k<<|,mid+,b,mid+,r);
}
inline void upd(int k,int a,int b,int l,int r)
{
if(tr[k].mx<=) return ;
if(l==r) {tr[k].sum=tr[k].mx=sqrt(tr[k].sum);return ;}
int mid=(l+r)>>;
if(mid>=b) upd(k<<,a,b,l,mid);
else if(mid<a) upd(k<<|,a,b,mid+,r);
else {upd(k<<,a,mid,l,mid);upd(k<<|,mid+,b,mid+,r);}
pshp(k);
}
int main()
{
int a,b,c;
n=read();
for(int i=;i<=n;i++) g[i]=read();
m=read();
build(,,n);
while(m--)
{
a=read(),b=read(),c=read();
if(a==) upd(,b,c,,n);
else printf("%lld\n",query(,b,c,,n));
}
}

Codeforces 920F. SUM and REPLACE / bzoj 3211 花神游历各国的更多相关文章

  1. BZOJ 3211: 花神游历各国( 线段树 )

    线段树...区间开方...明显是要处理到叶节点的 之前在CF做过道区间取模...差不多, 只有开方, 那么每个数开方次数也是有限的(0,1时就会停止), 最大的数10^9开方10+次也就不会动了.那么 ...

  2. BZOJ 3211: 花神游历各国【线段树区间开方问题】

    3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 3514  Solved: 1306[Submit][Status][Discu ...

  3. BZOJ 3038: 上帝造题的七分钟2 / BZOJ 3211: 花神游历各国 (线段树区间开平方)

    题意 给出一些数,有两种操作.(1)将区间内每一个数开方(2)查询每一段区间的和 分析 普通的线段树保留修改+开方优化.可以知道当一个数为0或1时,无论开方几次,答案仍然相同.所以设置flag=1变表 ...

  4. BZOJ 3211 花神游历各国 线段树平方开根

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3211 题目大意: 思路: 由于数据范围只有1e9,一个数字x开根号次数超过logx之后 ...

  5. bzoj 3211: 花神游历各国

    #include<cstdio> #include<cmath> #include<iostream> #define M 100006 using namespa ...

  6. BZOJ 3211 花神游历各国 (树状数组+并查集)

    题解:首先,单点修改求区间和可以用树状数组实现,因为开平方很耗时间,所以在这个方面可以优化,我们知道,开平方开几次之后数字就会等于1 ,所以,用数组记录下一个应该开的数,每次直接跳到下一个不是1的数字 ...

  7. Codeforces 920F - SUM and REPLACE

    920F - SUM and REPLACE 思路1: 线段树(982 ms) 每个点最多更新6次 代码: #include<bits/stdc++.h> using namespace ...

  8. Codeforces 920F - SUM and REPLACE 【线段树】

    <题目链接> 题目大意: 给你一个序列,有两个操作,一个是求区间 l - r 的和,另一个是对区间l-r的元素修改值,x=d(x),d(x)为x的因子个数. 解题分析: 因为可能有多次修改 ...

  9. 2018.12.15 codeforces 920F. SUM and REPLACE(线段树)

    传送门 线段树入门题. 给你一个序列:支持区间修改成自己的约数个数,区间求和. 实际上跟区间开方一个道理. 2的约数个数为2,1的约数个数为1,因此只要区间的最大值小于3就不用修改否则就暴力修改. 因 ...

随机推荐

  1. Redis系列(一)--基础API

    Redis:Remote Dictionary Server 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件.C语言实现,单线程 Redis特性: 1.速度快 ...

  2. C++ Primer(第4版)-学习笔记-第3部分:类和数据抽象

    第12章 类       每个类可以没有成员,也可以定义多个成员,成员可以是数据.函数或类型别名. 成员函数必须在类内部声明,可以在类内部定义,也可以在类外部定义.如果在类内部定义,就默认是内联函数. ...

  3. UVA - 208 Firetruck(并查集+dfs)

    题目: 给出一个结点d和一个无向图中所有的边,按字典序输出这个无向图中所有从1到d的路径. 思路: 1.看到紫书上的提示,如果不预先判断结点1是否能直接到达结点d,上来就直接dfs搜索的话会超时,于是 ...

  4. 验证DNS解析失败:解决办法之一

    今天晚上练习简单的DNS解析验证: 环境是在一台虚拟机上搭建,另一台虚拟机验证,步骤如下: 虚拟机A: 1.安装软件包 bind  和bind-chroot[root@svr7 ~]# yum -y ...

  5. 窥探原理:实现一个简单的前端代码打包器 Roid

    roid roid 是一个极其简单的打包软件,使用 node.js 开发而成,看完本文,你可以实现一个非常简单的,但是又有实际用途的前端代码打包工具. 如果不想看教程,直接看代码的(全部注释):点击地 ...

  6. git 连接github.com 并配置密钥

    传送门:http://www.jianshu.com/p/ff1034ed270e #备份ssh cd ~/.ssh $ ls $ mkdir key_backup //创建备份文件夹 $ cp id ...

  7. 爬虫----Web_WeChat

    流程: 打开的web_wechat,就有出现二维码,在network中,name中login?loginicon中,status的状态是pending,pending的意思是前端发送了一个请求,但是还 ...

  8. Latex Notes

    latex Table of Contents 1. Presentation/Slides with Beamer 2. Drawing in LaTex With TikZ 3. Tracked ...

  9. 洛谷 1894 [USACO4.2]完美的牛栏The Perfect Stall

    [题解] 其实是个二分图最大匹配的模板题,直接上匈牙利算法就好了. #include<cstdio> #include<algorithm> #define N 1010 #d ...

  10. StringBuilder的构造方法

    /* * String和StringBuilder的区别: * String的内容是固定的 * StringBuilder的内容是可变的 * 构造方法: * StringBuilder() * 成员方 ...