梦,才是最真的现实

导航

codeforces251/D/线段树

线段树对区间取模。

考试前就想写的题目QAQ,cxlove点了一下之后知道是什么回事了,先说下做法,暴力更新就行了,维护区间的最大值,每次把要取模的区间的最大值取出来,暴力更新,由于取模的性质可以保证每次取模之后至少比原数的一半还少,所以整体复杂度还是比较低的。

现在简单证明下a%b < a / 2:

首先我们先设b = ka , k属于(0,1]

1.若k <= 0.5 , 则根据%的运算符很容易得到a % b < 0.5a.

2.若k > 0.5,直接用减法可以替代取模运算,a -= b,容易得出a = (1 - k)a < 0.5a;

证毕。


贴代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define lson l,m,rt << 1
#define rson m + 1,r,rt << 1 | 1
#define lc rt << 1
#define rc rt << 1 | 1
using namespace std;

const int N = 100050;
int n,q;

struct Node
{
    LL sum,maxVal;
    int from;
}node[N << 2];

inline void pushUp(int rt){
    node[rt].sum = node[lc].sum + node[rc].sum;
    if(node[lc].maxVal < node[rc].maxVal){
        node[rt].maxVal = node[rc].maxVal;
        node[rt].from = node[rc].from;
    }
    else{
        node[rt].maxVal = node[lc].maxVal;
        node[rt].from = node[lc].from;
    }
}

inline void build(int l,int r,int rt){
    if(l == r){
        scanf("%I64d",&node[rt].sum);
        node[rt].maxVal = node[rt].sum;
        node[rt].from = l;
        return ;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    pushUp(rt);
}

inline void assign(int p,int val,int l,int r,int rt){
    // printf("val:%d\n",val);
    if(l == r){
        node[rt].sum = node[rt].maxVal = val;
        return ;
    }
    int m = (l + r) >> 1;
    if(p <= m) assign(p,val,lson);
    else assign(p,val,rson);
    pushUp(rt);
}

inline pair<int,int> queryMax(int L,int R,int l,int r,int rt){
    if(L <= l && r <= R)
        return make_pair(node[rt].maxVal,node[rt].from);
    int m = (l + r) >> 1;
    pair<int,int> ret = make_pair(-1,1);
    if(L <= m) ret = queryMax(L,R,lson);
    if(R > m) ret = max(ret,queryMax(L,R,rson));
    return ret;
}

inline LL query(int L,int R,int l,int r,int rt){
    if(L <= l && r <= R){
        return node[rt].sum;
    }
    int m = (l + r) >> 1;
    LL ret = 0;
    if(L <= m) ret += query(L,R,lson);
    if(R > m) ret += query(L,R,rson);
    return ret;
}

int main(){
    // freopen("input.txt","r",stdin);
    // freopen("output.txt","w",stdout);
    scanf("%d%d",&n,&q);
    build(1,n,1);
    while(q --){
        int op;scanf("%d",&op);
        if(op == 1){
            int l,r;scanf("%d%d",&l,&r);
            printf("%I64d\n",query(l,r,1,n,1));
        }
        else if (op == 2){
            int l,r,x;scanf("%d%d%d",&l,&r,&x);
            while(true){
                pair<int,int> ret = queryMax(l,r,1,n,1);
                // printf("l:%d  r:%d  max:%d  from:%d new:%d\n",l,r,ret.first,ret.second,ret.first%x);
                if(ret.first >= x){
                    assign(ret.second,ret.first % x,1,n,1);
                }
                else break;
            }
        }
        else{
            int k,x;scanf("%d%d",&k,&x);
            assign(k,x,1,n,1);
        }
    }
    return 0;
}

  

posted on 2014-07-04 11:12  梦,才是最真的现实  阅读(331)  评论(0编辑  收藏  举报