438D - The Child and Sequence

#include <stdio.h>
#include <algorithm>

using namespace std;

#define lson num << 1
#define rson num << 1 | 1
#define MAXN 100005
typedef long long ll;
 int a[MAXN << 1];
struct node
{
    int l,r;
    ll Max,sum;
}tree[MAXN << 2];
void pushup(ll rt){

    tree[rt].Max = max(tree[rt << 1].Max,tree[rt << 1|1].Max);
    tree[rt].sum = tree[rt << 1].sum + tree[rt << 1|1].sum;
}

// void build(int num,int l,int r)
// {
//     tree[num].l = l;
//     tree[num].r = r;
//     if(l == r) {
//         //scanf("%I64d",&tree[num].Max);
//         tree[num].sum = tree[num].Max = a[l];
//         return;
//     }
//     int mid = (l + r) >> 1;
//     build(lson,l,mid);
//     build(rson,mid + 1,r);
//     pushup(num);
// }
void build(ll rt,ll l ,ll r){
    tree[rt].l = l , tree[rt].r = r;
    if(l == r){
        tree[rt].sum = tree[rt].Max = a[l];
        return;
    }
    ll mid = (l + r) >> 1;
    build(rt << 1, l , mid);
    build(rt <<1|1,mid + 1,r);

    pushup(rt);
}

// ll query(int num,int l,int r)
// {
//     if(tree[num].l == l && tree[num].r == r) {
//         return tree[num].sum;
//     }
//     int mid = (tree[num].l + tree[num].r) >> 1;
//     if(r <= mid) {
//         return query(lson,l,r);
//     }
//     else if(l > mid) {
//         return query(rson,l,r);
//     }
//     else {
//         return query(lson,l,mid) + query(rson,mid + 1,r);
//     }
// }
ll query(ll rt,ll l,ll r){
    if(tree[rt].l == l && r == tree[rt].r){
        return tree[rt].sum;
    }//cout << rt << endl;
    ll mid = (tree[rt].l + tree[rt].r) >> 1;
    if(r <= mid) return query(rt << 1,l ,r);
    else if(l > mid) return query(rt << 1|1,l,r);
    else return query(rt << 1,l, mid) + query(rt << 1|1 , mid + 1, r);
}

// void update1(int num,int l,int r,int mod)
// {
//     if(tree[num].Max < mod) {
//         return;
//     }
//     if(tree[num].l == tree[num].r) {
//         tree[num].Max %= mod;
//         tree[num].sum %= mod;
//         return;
//     }
//     int mid = (tree[num].l + tree[num].r) >> 1;
//     if(r <= mid) {
//         update1(lson,l,r,mod);
//     }
//     else if(l > mid) {
//         update1(rson,l,r,mod);
//     }
//     else {
//         update1(lson,l,mid,mod),update1(rson,mid + 1,r,mod);
//     }
//     pushup(num);
// }

void update1(ll rt,ll l ,ll r ,ll v){
   // cout << t[rt].maxx << endl;
    if(v > tree[rt].Max) return;
    if( tree[rt].l == tree[rt].r){

        tree[rt].Max %= v; tree[rt].sum  %= v;
       // cout << t[rt].sum << " " << 111 << endl;
        return;
    }

    //
    ll mid = (tree[rt].l + tree[rt].r) >> 1;
    if(r <= mid) update1(rt << 1,l ,r,v);
    else if(l > mid) update1(rt << 1|1,l,r,v);
    else update1(rt << 1,l, mid,v) , update1(rt << 1|1 , mid + 1, r,v);
    pushup(rt);
}

// void update2(int num,int pos,int val)
// {
//     if(tree[num].l == tree[num].r && tree[num].l == pos) {
//         tree[num].sum = val;
//         tree[num].Max = val;
//         return;
//     }
//     int mid = (tree[num].l + tree[num].r) >> 1;
//     if(pos <= mid) {
//         update2(lson,pos,val);
//     }
//     else {
//         update2(rson,pos,val);
//     }
//     pushup(num);
// }

void update2(ll rt,ll x,ll v){
    if(tree[rt].l == tree[rt].r && tree[rt].l == x){
        tree[rt].Max = tree[rt].sum = v;
        return;
    }
    ll mid = (tree[rt].l + tree[rt].r) >> 1;
    if(x <= mid) update2(rt << 1,x , v);
    else update2(rt << 1|1,x , v);
    pushup(rt);
}

// int main(void)
// {
//     int n,m;
//     scanf("%d%d",&n,&m);
//     for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
//     build(1,1,n);
//     while(m--) {
//         int op,l,r,pos,x;
//         scanf("%d",&op);
//         if(op == 1) {
//             scanf("%d%d",&l,&r);
//             printf("%I64d\n",query(1,l,r));
//         }
//         else if(op == 2) {
//             scanf("%d%d%d",&l,&r,&x);
//             update1(1,l,r,x);
//         }
//         else {
//             scanf("%d%d",&pos,&x);
//             update2(1,pos,x);
//         }

//     }
//     return 0;
// }

int main(int argc, char const *argv[])
{
    ll n , m ;
    scanf("%lld%lld",&n,&m);
    for(ll i = 1;i <= n ; i++) scanf("%lld",&a[i]);
    build(1,1,n);
//for(ll i = 1;i <= 40; i++) cout << t[i].sum << endl;
    while(m--){
        ll a;
        scanf("%lld",&a);
        if(a == 1){
            ll b , c;
            scanf("%lld%lld",&b,&c);
            printf("%lld\n",query(1,b,c));
        }else if(a == 2){
            ll b ,c, pos;
            scanf("%lld%lld%lld",&b,&c,&pos);
            update1(1,b,c,pos);
        }else{
            ll b , c;
            scanf("%lld%lld",&b,&c);
            update2(1,b,c);
        }
    }
    return 0;
}

线段树重要思想

线段树单点修改的本质就是区间修改

本题是对所有数取模,如果对区间和取模,必定会影响子节点,那么便只能对子节点取模

但是如果一个一个取模,便会有超时的危险

那么我们就可以利用剪枝的思想,对小于mod的数/区间,直接返回

只对大于mod的数进行取模,那么便能降低复杂度。

#include <stdio.h>
#include <algorithm>

using namespace std;

#define lson num << 1
#define rson num << 1 | 1
#define MAXN 100005
typedef long long ll;

struct node
{
    int l,r;
    ll Max,sum;
}tree[MAXN << 2];
void pushup(int num)
{
    tree[num].Max = max(tree[lson].Max,tree[rson].Max);
    tree[num].sum = tree[lson].sum + tree[rson].sum;
}
void build(int num,int l,int r)
{
    tree[num].l = l;
    tree[num].r = r;
    if(l == r) {
        scanf("%I64d",&tree[num].Max);
        tree[num].sum = tree[num].Max;
        return;
    }
    int mid = (l + r) >> 1;
    build(lson,l,mid);
    build(rson,mid + 1,r);
    pushup(num);
}
ll query(int num,int l,int r)
{
    if(tree[num].l >= l && tree[num].r <= r) {
        return tree[num].sum;
    }
    int mid = (tree[num].l + tree[num].r) >> 1;
    if(r <= mid) {
        return query(lson,l,r);
    }
    else if(l > mid) {
        return query(rson,l,r);
    }
    else {
        return query(lson,l,mid) + query(rson,mid + 1,r);
    }
}
void update1(int num,int l,int r,int mod)
{
    if(tree[num].Max < mod) {
        return;
    }
    //因为修改的是最大值,不是区间修改,所以是这个
    if(tree[num].l == tree[num].r) {
        tree[num].Max %= mod;
        tree[num].sum %= mod;
        return;
    }
    int mid = (tree[num].l + tree[num].r) >> 1;
    if(r <= mid) {
        update1(lson,l,r,mod);
    }
    else if(l > mid) {
        update1(rson,l,r,mod);
    }
    else {
        update1(lson,l,mid,mod),update1(rson,mid + 1,r,mod);
    }
    pushup(num);
}
void update2(int num,int pos,int val)
{
    if(tree[num].l == tree[num].r ) {
        tree[num].sum = val;
        tree[num].Max = val;
        return;
    }
    int mid = (tree[num].l + tree[num].r) >> 1;
    if(pos <= mid) {
        update2(lson,pos,val);
    }
    else {
        update2(rson,pos,val);
    }
    pushup(num);
}
int main(void)
{
    int n,m;
    scanf("%d%d",&n,&m);
    build(1,1,n);
    while(m--) {
        int op,l,r,pos,x;
        scanf("%d",&op);
        if(op == 1) {
            scanf("%d%d",&l,&r);
            printf("%I64d\n",query(1,l,r));
        }
        else if(op == 2) {
            scanf("%d%d%d",&l,&r,&x);
            update1(1,l,r,x);
        }
        else {
            scanf("%d%d",&pos,&x);
            update2(1,pos,x);
        }

    }
    return 0;
}

原文地址:https://www.cnblogs.com/DWVictor/p/11198271.html

时间: 2024-08-30 12:47:36

438D - The Child and Sequence的相关文章

CF(438D) The Child and Sequence(线段树)

题意:对数列有三种操作: Print operation l,?r. Picks should write down the value of . Modulo operation l,?r,?x. Picks should perform assignment a[i]?=?a[i] mod x for each i (l?≤?i?≤?r). Set operation k,?x. Picks should set the value of a[k] to x (in other words

CodeForces 438D The Child and Sequence(线段树)

题目:http://codeforces.com/problemset/problem/438/D 一个数取模n%m,有两种情况. 1.m>n, n%m=n; 2.m<=n, n%m<=n/2; 所以当m>n时,取模操作可以忽略. 每个a[i]最多需要log(a[i])次取模操作变为0,因此我们可以对所有取模进行暴力更新.最多要更新n*log(a[i])次,由于单次更新复杂度为log(n),所以总复杂度为n*logn*log(a[i]). #include <bits/std

Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间求和+点修改+区间取模

D. The Child and Sequence At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at him. A lot of important things were lost, in particular the favorite sequence of Picks. Fortunately, Picks remembers how to

【CodeForces 438D 】The Child and Sequence

题意 要求支持三种操作  1.区间求和  2.单点修改  3.区间取模 分析 问题主要在于区间取模 需要多维护一个区间最大值,当最大值已经小于模数的时候就不需要操作了 [先开始读错题了,写了个区间修改哎我没救了] #include<bits/stdc++.h> using namespace std; #define N 110000 #define ll long long #define lc (p<<1) #define rc (p<<1|1) #define m

codeforces438D The Child and Sequence

题面:codeforces438D 正解:线段树. 这题好像是$picks$出的题,然后无限弱化才上的$cf$.. 区间取模,每个数取模以后至少$/2$,所以暴力搞即可. 证明:若$p<x/2$,那么$x \ mod \ p<x/2$:若$p>x/2$,那么$ x \ mod \ p=x-p<x/2$. 维护一个区间最大值,如果$<p$那么就直接退出,否则把这个区间递归做再取模. 1 //It is made by wfj_2048~ 2 #include <algor

Codeforces Round #250 (Div. 1) D. The Child and Sequence (线段树)

题目链接:http://codeforces.com/problemset/problem/438/D 给你n个数,m个操作,1操作是查询l到r之间的和,2操作是将l到r之间大于等于x的数xor于x,3操作是将下标为k的数变为x. 注意成段更新的时候,遇到一个区间的最大值还小于x的话就停止更新. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5

CF438D The Child and Sequence

外国人的数据结构题真耿直 唯一有难度的操作就是区间取模,然而这个东西可以暴力弄一下,因为一个数$x$被取模不会超过$logn$次. 证明如下(假设$x Mod   y$): 如果$y \leq \frac{x}{2}$那么$x$取模之后会小于$\frac{x}{2}$,而如果$y > \frac{x}{2}$时,$x$取模之后一定也会小于$\frac{x}{2}$ 然后就暴力一个一个取过去就好了,还有一个算是剪枝的优化,我们可以顺便维护一下区间最大值,如果区间最大值都小于当前的模数的话,那么就直

cf250D. The Child and Sequence(线段树 均摊复杂度)

题意 题目链接 单点修改,区间mod,区间和 Sol 如果x > mod ,那么 x % mod < x / 2 证明: 即得易见平凡, 仿照上例显然, 留作习题答案略, 读者自证不难. 反之亦然同理, 推论自然成立, 略去过程Q.E.D., 由上可知证毕. 然后维护个最大值就做完了.. 复杂度不知道是一个log还是两个log,大概是两个吧(线段树一个+最多改log次.) #include<bits/stdc++.h> #define Pair pair<int, int&g

CF438D The Child and Sequence 线段树

给定数列,区间查询和,区间取模,单点修改. n,m小于10^5 ...当区间最值小于模数时,就直接返回就好啦~ #include<cstdio> #include<iostream> #define R register int #define ls (tr<<1) #define rs (tr<<1|1) using namespace std; inline long long g() { register long long ret=0,fix=1;