题目大意:

一个数列 支持两种操作

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. Mybatis学习总结三(动态SQL)

    通过mybatis提供的各种标签方法实现动态拼接sql. 一.if 和 where <select id="findUserList" parameterType=" ...

  2. 日常开发需要掌握的Git命令

    本人待的两家公司,一直都是用的SVN,Git我只是自己私下学习和开发小项目的时候用过,工作一直没有使用过,但还是要学的... Git是最好的分布式版本控制系统 工作流程 SVN和Git的区别 SVN是 ...

  3. bazel和TensorFlow安装

    bazel安装:https://docs.bazel.build/versions/master/install-ubuntu.html#install-with-installer-ubuntu 安 ...

  4. fiddler培训

    fiddler  在客户端和服务器中间做一个代理 ,只能截获http或HTTPS的请求 代理地址127.0.0.1  端口8888 反向代理,正向代理 浏览器上设置代理地址和端口 左边是session ...

  5. [bzoj1004][HNOI2008][Cards] (置换群+Burnside引理+动态规划)

    Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红 ...

  6. 使用nfs3将hdfs挂载到本地或远程目录(非kerberos适用)

    最基本的配置方法,aix.kerberos等的操作详见http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/Hdf ...

  7. Windows学习总结(10)——Windows系统中常用的CMD命令详解

    1.ping命令 ping是电脑网络故障诊断中的常用的命令,它的作用是用来检查网络是否通畅或者网络连接速度.我们来看一下PING命令的具体表述. 日常的诊断过程中我们最常用到的就是诊断连接是否通畅. ...

  8. 不动点(Fixed Point)

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51735818 在数学中,函数的不动点( ...

  9. Cx的治疗

    题目背景 「Cx的故事」众所周知,Cx是一个宇宙大犇.由于Cx在空中花园失足摔下,导致他那蕴含着无穷智慧的大脑受到了严重的损伤,许多的脑神经断裂.于是,Cx的wife(有么?)决定请巴比伦最好的医师治 ...

  10. 解决使用myeclipse电脑卡的问题

    1. 原因:myeclipse会自动更新,因此会占用大量内存 2. 解决方法: (1)window->Perferences->General->Startup and Shutdo ...