Codecraft-18 and Codeforces Round #458 D. Bash and a Tough Math Puzzle(线段树)

2024-01-29 12:38

本文主要是介绍Codecraft-18 and Codeforces Round #458 D. Bash and a Tough Math Puzzle(线段树),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Bash likes playing with arrays. He has an array a1, a2, ... an of n integers. He likes to guess the greatest common divisor (gcd) of different segments of the array. Of course, sometimes the guess is not correct. However, Bash will be satisfied if his guess is almost correct.

Suppose he guesses that the gcd of the elements in the range [l, r] of a is x. He considers the guess to be almost correct if he can change at most one element in the segment such that the gcd of the segment is x after making the change. Note that when he guesses, he doesn't actually change the array — he just wonders if the gcd of the segment can be made x. Apart from this, he also sometimes makes changes to the array itself.

Since he can't figure it out himself, Bash wants you to tell him which of his guesses are almost correct. Formally, you have to process qqueries of one of the following forms:

  • 1 l r x — Bash guesses that the gcd of the range [l, r] is x. Report if this guess is almost correct.
  • 2 i y — Bash sets ai to y.

Note: The array is 1-indexed.

Input

The first line contains an integer n (1 ≤ n ≤ 5·105)  — the size of the array.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 109)  — the elements of the array.

The third line contains an integer q (1 ≤ q ≤ 4·105)  — the number of queries.

The next q lines describe the queries and may have one of the following forms:

  • 1 l r x (1 ≤ l ≤ r ≤ n, 1 ≤ x ≤ 109).
  • 2 i y (1 ≤ i ≤ n, 1 ≤ y ≤ 109).

Guaranteed, that there is at least one query of first type.

Output

For each query of first type, output "YES" (without quotes) if Bash's guess is almost correct and "NO" (without quotes) otherwise.

Examples
input
3
2 6 3
4
1 1 2 2
1 1 3 3
2 1 9
1 1 3 2
output
YES
YES
NO
input
5
1 2 3 4 5
6
1 1 4 2
2 3 6
1 1 4 2
1 1 5 2
2 5 10
1 1 5 2
output
NO
YES
NO
YES

题意:给你一个数组,然后有两种操作,第一种是问一个区间[l,r]的gcd是否几乎是x,什么是几乎是x呢,就是改变[l,r]中最多一个数字使得区间的gcd可以为x(实际上并没有改变这个数字),第二种是改变数组中的一个数字。

思路:本来是想用线段树做区间gcd,然后如果要查询[l,r],就先判断[l,mid]和[mid+1,r]这两半区间是否最多有一个不是x的倍数,如果两个都不是x的倍数,那么就不可能改变为x;如果两个都是x的倍数,那么这一整段的gcd肯定可以是x;如果有一个不是x的倍数,那么就递归处理这一段。代码如下:

bool judge(int l,int r,int x)
{int m = (l+r)/2;int q1 = query(l,m,1,n,1);int q2 = query(m+1,r,1,n,1);if(q1 % x != 0 && q2 % x != 0)return false;if(q1 % x == 0 && q2 % x == 0)return true;if(l == m || m+1 == r)return true;if(q1 % x != 0)return judge(l,m,x);if(q2 % x != 0)return judge(m+1,r,x);
}
这种的复杂度是q乘上logn的平方,按道理来说不应该T,但是T12,然后把它改成了while形式,还有其他各种优化,终于强行怼过了样例PP了,可是还是没有逃过终测。


最后换成了直接在query查询线段树的时候就做上面的工作,这样就可以省掉一个log。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>using namespace std;int gcd(int a,int b)
{if(b == 0)return a;elsereturn gcd(b,a%b);
}
const int maxn = 500010;
int sum[maxn*4];void PushUp(int rt)
{sum[rt] = gcd(sum[rt*2],sum[rt*2+1]);
}void build(int l, int r, int rt)
{if (l == r){scanf("%d",&sum[rt]);return;}int m = (l + r) / 2;build(l, m, rt*2);build(m + 1, r, rt*2+1);PushUp(rt);
}
void update(int p,int c, int l, int r, int rt)
{if(l == r){sum[rt] = c;return;}int m = (l + r) / 2;if(p <= m)update(p, c, l, m, rt*2);elseupdate(p, c, m + 1, r, rt*2+1);PushUp(rt);
}
int cnt,x;
void query(int ll, int rr, int l, int r, int rt)
{if(cnt > 1) //记得加这句剪枝return;if(l == r){cnt++;return;}int m = (l + r) / 2;int ret = 0;if(ll <= m && sum[rt*2] % x != 0)query(ll, rr, l, m, rt*2);if(rr > m && sum[rt*2+1] % x != 0)query(ll, rr, m + 1, r, rt*2+1);
}int main(void)
{int n,q,i,j;scanf("%d",&n);build(1,n,1);scanf("%d",&q);while(q--){int op;scanf("%d",&op);if(op == 1){int l,r;scanf("%d%d%d",&l,&r,&x);cnt = 0;query(l,r,1,n,1);if(cnt <= 1)printf("YES\n");elseprintf("NO\n");}else{int p,c;scanf("%d%d",&p,&c);update(p,c,1,n,1);}}return 0;
}


这篇关于Codecraft-18 and Codeforces Round #458 D. Bash and a Tough Math Puzzle(线段树)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/656920

相关文章

Python实现数据清洗的18种方法

《Python实现数据清洗的18种方法》本文主要介绍了Python实现数据清洗的18种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录1. 去除字符串两边空格2. 转换数据类型3. 大小写转换4. 移除列表中的重复元素5. 快速统

如何使用 Bash 脚本中的time命令来统计命令执行时间(中英双语)

《如何使用Bash脚本中的time命令来统计命令执行时间(中英双语)》本文介绍了如何在Bash脚本中使用`time`命令来测量命令执行时间,包括`real`、`user`和`sys`三个时间指标,... 使用 Bash 脚本中的 time 命令来统计命令执行时间在日常的开发和运维过程中,性能监控和优化是不

bat脚本启动git bash窗口,并执行命令方式

《bat脚本启动gitbash窗口,并执行命令方式》本文介绍了如何在Windows服务器上使用cmd启动jar包时出现乱码的问题,并提供了解决方法——使用GitBash窗口启动并设置编码,通过编写s... 目录一、简介二、使用说明2.1 start.BAT脚本2.2 参数说明2.3 效果总结一、简介某些情

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

poj 1127 线段相交的判定

题意: 有n根木棍,每根的端点坐标分别是 px, py, qx, qy。 判断每对木棍是否相连,当他们之间有公共点时,就认为他们相连。 并且通过相连的木棍相连的木棍也是相连的。 解析: 线段相交的判定。 首先,模板中的线段相交是不判端点的,所以要加一个端点在直线上的判定; 然后,端点在直线上的判定这个函数是不判定两个端点是同一个端点的情况的,所以要加是否端点相等的判断。 最后

HDU4737线段树

题目大意:给定一系列数,F(i,j)表示对从ai到aj连续求或运算,(i<=j)求F(i,j)<=m的总数。 const int Max_N = 100008 ;int sum[Max_N<<2] , x[Max_N] ;int n , m ;void push_up(int t){sum[t] = sum[t<<1] | sum[t<<1|1] ;}void upd