zoukankan      html  css  js  c++  java
  • Codeforces 438D:The Child and Sequence

    简要题意:
    n个数,m种操作。
    操作一:查询区间和
    操作二:区间[l,r]对x取模
    操作三:单点赋值
    思路:

    非常经典的区间取模题。

    吕凯风出的div1的题。
    这种题的关键在于分析复杂度,本来如果没有第三个操作,会非常放心大胆地写。
    因为取模只会让值越变越小,跟区间开根基本上一个道理,该暴力的时候暴力,但是要控制暴力的次数。
    单点赋值的存在动摇了我采用这种做法的决心。
    然而在题解中,vfleaking分析了一波复杂度,其实这样做还是OK的。
    取模的性质保证了,如果一旦被取模的数大于等于模数,在取模后会严格小于原先的一半,也就是说一个数X只会发生[logX]次实际有意义的取模。
    为了保证有意义的取模,我们需要维护区间最大值,这个非常好写。
    vfleaking把每个数能发生实际取模的次数称为这个数的energy,那么初始状态下的总energy是O(Nlog(ai))的。
    维护区间最大值保证了每次实际暴力取模时,会使整个的energy之和至少减少1.
    而单点赋值,最大能让整个区间的energy之和增加O(log(ai)).
    因此整体的最大energy是O((N+M)log(ai))的。每次减小1的复杂度是均摊O(logN)(线段树深度)的。
    因此整体的复杂度是O((N+M)log(ai)logN)的。
    两个log在这道题依然是OK的能过的。

    #include<bits/stdc++.h>
    #define lson(p) p<<1
    #define rson(p) p<<1|1
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+10;
    int n,m,l,r,x,op;
    int a[maxn];
    struct node
    {
        int mx;
        ll sum;
    }b[4*maxn];
    void pushup(int p)
    {
        b[p].mx=max(b[lson(p)].mx,b[rson(p)].mx);
        b[p].sum=b[lson(p)].sum+b[rson(p)].sum;
    }
    void build(int p,int l,int r)
    {
        if (l==r) {
            b[p].mx=b[p].sum=a[l];
            return ;
        }
        int mid=(l+r)>>1;
        build(lson(p),l,mid);
        build(rson(p),mid+1,r);
        pushup(p);
    }
    void modify(int p,int l,int r,int L,int R,int v)
    {
        if (L<=l&&r<=R) {
            if (b[p].mx<v) return ;
            if (l==r) {
                b[p].mx%=v; b[p].sum%=v;
                return ;
            }
            int mid=(l+r)>>1;
            modify(lson(p),l,mid,L,R,v);
            modify(rson(p),mid+1,r,L,R,v);
            pushup(p);
            return ;
        }
        int mid=(l+r)>>1;
        if (L<=mid) modify(lson(p),l,mid,L,R,v);
        if (R>mid) modify(rson(p),mid+1,r,L,R,v);
        pushup(p);
    }
    void setVal(int p,int l,int r,int pos,int v)
    {
        if (l==r) {
            b[p].sum=b[p].mx=v;
            return ;
        }
        int mid=(l+r)>>1;
        if (pos<=mid) setVal(lson(p),l,mid,pos,v);
        else setVal(rson(p),mid+1,r,pos,v);
        pushup(p);
    }
    ll getSum(int p,int l,int r,int L,int R)
    {
        if (L<=l&&r<=R) return b[p].sum;
        int mid=(l+r)>>1;
        ll ans=0;
        if (L<=mid) ans+=getSum(lson(p),l,mid,L,R);
        if (R>mid) ans+=getSum(rson(p),mid+1,r,L,R);
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        build(1,1,n);
        while (m--) {
            scanf("%d",&op);
            if (op==1) {
                scanf("%d%d",&l,&r);
                printf("%lld
    ",getSum(1,1,n,l,r));
            }
            else if (op==2) {
                scanf("%d%d%d",&l,&r,&x);
                modify(1,1,n,l,r,x);
            }
            else {
                scanf("%d%d",&l,&x);
                setVal(1,1,n,l,x);
            }
        }
        return 0;
    }
  • 相关阅读:
    python的eval、exec函数使用总结
    sorted()&enumerate()
    递归
    作用域
    Python3 os.stat() 方法
    android 电容屏(一):电容屏基本原理篇
    Linux 2.6内核与Linux 3.0 的区别!
    struct device的成员变量bus_id到哪里去了?
    Linux内核中ioremap映射的透彻理解
    Android 通过串口模拟 模拟物理按键
  • 原文地址:https://www.cnblogs.com/xyw5vplus1/p/13781342.html
Copyright © 2011-2022 走看看