题目大意:

一个数列 支持两种操作

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. laydate.js 月份区间选择插件

    laydate.render({ elem: '#reservation2' , type: 'month' , range: true, //format: '2018/09', theme: '# ...

  2. CAD得到多行文本(com接口VB语言)

    主要用到函数说明: MxDrawXCustomFunction::Mx_GetMTextContent 得到多行文本的,不包括格式控制符中的字符串值,详细说明如下: 参数 说明 LONG lId 多行 ...

  3. vue组件---动态组件之多标签页面

    首先看下效果图 代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> & ...

  4. 使用SELECT语句检索数据

    使用SELECT语句检索数据select指令适用于SQL数据库SELECT 语句用于从数据库中选取数据.(指令不分大小写,选择的值除名字和一些有特殊意义的字符可不分大小写,from结束时一定要加;) ...

  5. 社交网络图中结点的“重要性”计算 (30 分) C++解法

    社交网络图中结点的"重要性"计算 (30 分) 在社交网络中,个人或单位(结点)之间通过某些关系(边)联系起来.他们受到这些关系的影响,这种影响可以理解为网络中相互连接的结点之间蔓 ...

  6. Game Rank(NCPC 2016 大模拟)

    题目: The gaming company Sandstorm is developing an online two player game. You have been asked to imp ...

  7. Linux mpstat-显示各个可用CPU的状态

    更多linux 性能监测与优化 关注:linux命令大全 mpstat命令指令主要用于多CPU环境下,它显示各个可用CPU的状态系你想.这些信息存放在/proc/stat文件中.在多CPUs系统里,其 ...

  8. js之定时器操作

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 【Codeforces 464A】No to Palindromes!

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 因为原序列没有任何长度超过2的回文串. 所以,我们在改变的时候,只要时刻保证改变位置s[i]和s[i-1]以及s[i-2]都不相同就好. 因为 ...

  10. NOIP1999 邮票面值设计

    题目描述 Description 给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1-MAX之 ...