ZOJ 3886 Nico Number (线段树)

题目地址:ZJU 3886

这个题需要想到一点,因为对一个数x不断取模的话,而且设定他小于模才会进行取余操作的话,那么最多只会进行logx次,因为每次取模都会使x最少折半。然后想到了这点就很好做了。对于区间取模更新操作可以直接暴力更新,维护一个最大值,如果这个区间的最大值小于模的话, 就不用继续向叶子更新了。然后其他的大于模的就更新到叶子节点。

然后对于NicoNumber来说,只有6,2的幂次和素数来说是符合的。所以可以预处理出来。然后就可以用线段树来维护了。

代码如下:

#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <set>
#include <stdio.h>
#include <time.h>
using namespace std;
#define LL long long
#define pi acos(-1.0)
#pragma comment(linker, "/STACK:1024000000")
#define root 1, n, 1
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double eqs=1e-9;
const int MAXN=100000+10;
bool isprime[MAXN*100], ok[MAXN*100];
int prime[MAXN*10];
int Max[MAXN<<2], sum[MAXN<<2];
void init()
{
        int tot=0, i, j;
        ok[0]=ok[1]=1;
        ok[6]=1;
        for(i=2;i<=10000000;i++){
                if(!isprime[i]) {
                        prime[tot++]=i;
                        ok[i]=true;
                }
                for(j=0;j<tot;j++){
                        if(i*prime[j]>10000000) break;
                        isprime[i*prime[j]]=true;
                        if(i%prime[j]==0) break;
                }
        }
        int x=2;
        while(x<=10000000){
                ok[x]=true;
                x<<=1;
        }
}
void PushUp(int rt)
{
        Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void Build(int l, int r, int rt)
{
        if(l==r){
                scanf("%d",&Max[rt]);
                sum[rt]=ok[Max[rt]];
                return ;
        }
        int mid=l+r>>1;
        Build(lson);
        Build(rson);
        PushUp(rt);
}
void Update1(int p, int x, int l, int r, int rt)
{
        if(l==r){
                Max[rt]=x;
                sum[rt]=ok[x];
                return ;
        }
        int mid=l+r>>1;
        if(p<=mid) Update1(p,x,lson);
        else Update1(p,x,rson);
        PushUp(rt);
}
void Update2(int ll, int rr, int x, int l, int r, int rt)
{
        if(ll<=l&&rr>=r){
                if(Max[rt]<x) return ;
        }
        if(l==r){
                Max[rt]%=x;
                sum[rt]=ok[Max[rt]];
                return ;
        }
        int mid=l+r>>1;
        if(ll<=mid) Update2(ll,rr,x,lson);
        if(rr>mid) Update2(ll,rr,x,rson);
        PushUp(rt);
}
int Query(int ll, int rr, int l, int r, int rt)
{
        if(ll<=l&&rr>=r){
                return sum[rt];
        }
        int mid=l+r>>1, ans=0;
        if(ll<=mid) ans+=Query(ll,rr,lson);
        if(rr>mid) ans+=Query(ll,rr,rson);
        return ans;
}
int main()
{
        int n, i, j, l, r, p, v, q, x;
        init();
        while(scanf("%d",&n)!=EOF){
                memset(Max,0,sizeof(Max));
                memset(sum,0,sizeof(sum));
                Build(root);
                scanf("%d",&q);
                while(q--){
                        scanf("%d",&x);
                        if(x==1){
                                scanf("%d%d",&l,&r);
                                printf("%d\n",Query(l,r,root));
                        }
                        else if(x==2){
                                scanf("%d%d%d",&l,&r,&v);
                                Update2(l,r,v,root);
                        }
                        else{
                                scanf("%d%d",&p,&v);
                                Update1(p,v,root);
                        }
                }
        }
        return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 17:25:13

ZOJ 3886 Nico Number (线段树)的相关文章

ZOJ 3886 Nico number(线段树)

Nico Number Time Limit: 2 Seconds      Memory Limit: 262144 KB Kousaka Honoka and Minami Kotori are playing a game about a secret of Yazawa Nico. When the game starts, Kousaka Honoka will give Minami Kotori an array A of N non-negative integers. Ther

ZOJ 3886 Nico Number(筛素数+Love(线)Live(段)树)

problemCode=3886">ZOJ 3886 题意: 定义一种NicoNico数x,x有下面特征: 全部不大于x且与x互质的数成等差数列,如x = 5 ,与5互素且不大于5的数1,2,3,4成等差数列.则5是一个NicoNico数. 再定义三种操作: 1.南小鸟询问[L, R]内有多少个NicoNico数: 2.果皇把[L, R]内的数全部对v取余: 3.果皇将第K个数换成X. 然后给你一个数列,并对这个数列运行若干操作 思路: 这样的问题果断要用LoveLive树线段树来做! 首

ZOJ 2859 二维线段树

思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了:但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后在第二维就只有pushup操作,在第一维线段树没有pushup操作.要是在第一维也有pushup操作的话,那就不用单点查询那么慢了.不过也A了,想找题即在二维同时进行pushup和pushdown操作的. #include<iost

Hdu1394Minimum Inversion Number线段树

这个网上一搜一大堆,就是先求一个,其余的for一遍搞出来. #include<stdio.h> #include<stdlib.h> #define max 5555 int sum[max * 4]; int min(int a, int b) { if (a>b) return b; else return a; } void fuqin(int a) { sum[a] = sum[a * 2] + sum[a * 2 + 1]; } void build(int l,

Minimum Inversion Number(线段树单点更新+逆序数)

Minimum Inversion Number(线段树单点更新+逆序数) Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy

hdu 1394 Minimum Inversion Number 线段树 点更新

// hdu 1394 Minimum Inversion Number 线段树 点更新 // // 典型线段树的单点更新 // // 对于求逆序数,刚开始还真的是很年轻啊,裸的按照冒泡排序 // 求出最初始的逆序数,然后按照公式递推,结果就呵呵了 // // 发现大牛都是用线段树和树状数组之类的做的,而自己又在学 // 线段树,所以就敲了线段树. // // 线段树的节点保存一段区间( L,R )内0,1...n一共出现了多少个. // 因为每个数是0,1,2...n-1且没有重复的数字. /

HDU1394_Minimum Inversion Number(线段树/逆序数)

解题报告 题目传送门 题意: 给n个数,每次左移一位,求最小逆序数. 思路: 如果每次左移一位求一次逆序数肯定不行的. 可以知道,每次左移一位,也就是第一个数移到最后一位,逆序数应该减去第一个数以后比第一个数小的个数,再加上比第一个数大的个数. 原本用线段树求出每一位后面比这一位小的个数再用上面的办法求最小逆序数,没有想到每一次移动会导致后面比它本身大的数都要加1. 这题巧妙就在这n个数都在0-n里面,且没有重复. 所以第一个数以后比第一个数小的个数就是第一个数的数值.比它大就是n-1-第一个数

HDU 1394 Minimum Inversion Number.(线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 ~~~~ 早起一发线段树,开心又快乐.这题暴力也能水过,同时线段树的效率也就体现的尤为明显了,看了大牛的博客,说是还可以用树状数组,点树和合并序列写,现在还不懂,留着以后在写吧. ~~~~ 大致题意:给定一个数字序列,同时由此可以得到n个序列, 要求从n个序列中找到逆序数最小的序列,输出最小逆序数. 首先介绍下逆序数的概念: 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面

POJ 2777 &amp;&amp; ZOJ 1610 &amp;&amp;HDU 1698 --线段树--区间更新

直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 -- 区间更新的话 分为 增减 或者 修改 主要就是个 laze 标记 就是延迟更新 对于区间更新的写法 一般是有2种 其一 仔细划分到每个细小的区间    另一 粗略划分 反正 ==我的代码里会给出2种写法 看自己喜好 hdu 1 //线段树 成段更新 ---> 替换 根结点的查询 2 3 #i