Naive Operations(线段树)

Naive Operations

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 502768/502768 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


 

Problem Description

In a galaxy far, far away, there are two integer sequence a and b of length n.
b is a static permutation of 1 to n. Initially a is filled with zeroes.
There are two kind of operations:
1. add l r: add one for al,al+1...ar
2. query l r: query ∑ri=lai/bi

 

 

Input

There are multiple test cases, please read till the end of input file.
For each test case, in the first line, two integers n,q, representing the length of a,b and the number of queries.
In the second line, n integers separated by spaces, representing permutation b.
In the following q lines, each line is either in the form 'add l r' or 'query l r', representing an operation.
1≤n,q≤100000 , 1≤lrn , there're no more than 5 test cases.

 

 

Output

Output the answer for each 'query', each one line.

 

 

Sample Input

 

5 12 1 5 2 4 3 add 1 4 query 1 4 add 2 5 query 2 5 add 3 5 query 1 5 add 2 4 query 1 4 add 2 5 query 2 5 add 2 2 query 1 5

 

 

Sample Output

 

1 1 2 4 4 6

 

思路:

设sum 为要查询的结果,因为只有两个操作,分别考虑如下:

如果是更新操作,那么区间内ai 的值会加1

但是因为ai/bi是下取整操作,因此ai的增加未必导致sum的变化。

如果到达某个区间sum不改变的话,我们打个lazy标记返回,其实不会浪费

太多时间。

那么,什么时候sum才会变化呢?比如区间最小的bi值是2,那么当ai的值达到2时

该区间sum的值就会发生变化了,具体怎么变化呢?

明显sum+=1;

那么什么区间会变化呢?

显然最小值所在的节点会变化。那么综合起来就是说,对于更新操作:

如果区间最小值(这里初始为bi,ai的加1相当于线段处的减1)为min

那么当min > 1 标记lazy返回

如果min等于1那么会更新到叶子,那么最多会有多少次更新到叶子呢?

因为b数组为1-n的排列,因此假设add的n次都是取最大的区间,那么1位置更新了 n次

2更新了n/2 ...... 总的为(1+1/2+1/3+....+1/n)*n    -----   n*logn。

但是只有当时最小值的节点会更新下去因此速度不会太慢。

那么更新操作就解决了,查询也就是一般的区间查询了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+100;

struct node
{
    int l,r,lz,mn;
    ll sum;
}T[maxn<<2];

int b[maxn];

void pushup(int i)
{
    T[i].mn = min(T[i<<1].mn,T[i<<1|1].mn);
    T[i].sum = T[i<<1].sum+T[i<<1|1].sum;
}

void pushdown(int i)
{
    T[i<<1].mn -= T[i].lz;
    T[i<<1|1].mn -= T[i].lz;
    T[i<<1].lz += T[i].lz;
    T[i<<1|1].lz += T[i].lz;
    T[i].lz = 0;
}

void build(int i,int l,int r)
{
    T[i].l = l;
    T[i].r = r;
    T[i].lz = 0;
    T[i].sum = 0;
    if(l == r)
    {
        T[i].mn = b[l];
        return;
    }
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    pushup(i);
}

void modify(int i,int l,int r)
{
    if(T[i].l == l && T[i].r == r)
    {
        if(T[i].mn > 1)
        {
            T[i].mn --;
            T[i].lz++;
            return;
        }
    }
    if(T[i].l == T[i].r)
    {
        T[i].mn = b[T[i].l];
        T[i].sum += 1;
        return;
    }
    int mid = (T[i].l + T[i].r) / 2;
    if(T[i].lz) pushdown(i);
    if(r <= mid) modify(i<<1,l,r);
    else if(l > mid) modify(i<<1|1,l,r);
    else{
        modify(i<<1,l,mid);
        modify(i<<1|1,mid+1,r);
    }
    pushup(i);
}

ll query(int i,int l,int r)
{
    if(T[i].l == l && T[i].r == r)
    {
        return T[i].sum;
    }
    int mid = (T[i].l + T[i].r)/2;
    if(r <= mid) return query(i<<1,l,r);
    else if(l > mid) return query(i<<1|1,l,r);
    else return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
}

int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&b[i]);
        }
        build(1,1,n);
        char s[15];
        int l,r;
        while(q--)
        {
            scanf("%s%d%d",s,&l,&r);
            if(s[0] == 'q')
            {
                printf("%lld\n",query(1,l,r));
            }
            else
            {
                modify(1,l,r);
            }
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值