2018 Multi-University Training Contest 2 &&HDU6315 Naive Operations【线段树】

                                            Naive Operations

                                Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 502768/502768 K (Java/Others)

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

 

【题目链接】 Naive Operations

【题意】

给出一个排列b[i],还有一个初始为0的a数组。现在有一系列操作,一种是add l r,代表给a数组[l,r]范围内加1,还有一种是query l r代表查询sigma(ai/bi) l<=i<=r

【思路】

对于bi来说,每给这个位置加bi次对答案的贡献加1

因为每个位置最多加q次,那么贡献的最大期望为(q/1+q/2+q/3+...+q/n),即约等于qlogn

那么我们就可以想到用线段树去维护每个位置被加了几次

但是正地去想很难维护出每次add后哪个位置对答案有了贡献,于是我们反地考虑,一开始每个位置的数值为bi,每次add的时候对区间[l,r]都减一,当有位置减到0的时候就说明对答案有贡献,这个贡献也可以用线段树去维护,同时将这个位置的数值重新更新为bi

上面说了贡献的最大期望不是很大,所以时间复杂度可以接受,查询时利用线段树查询区间和即可(本来想单独用树状数组维护前缀和,但是这样写会TLE)

 

#include <cstdio>
#include <bits/stdc++.h>
#include <cmath>
#include <map>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

typedef  long long ll;
const int maxn = 100005;
const ll mod = 1e9+7;
const int INF = 1e9;
const double eps = 1e-6;

int n,q;
int num[maxn];
int tree[maxn<<2];
int flag[maxn<<2];
int ans[maxn<<2];

void pushup(int rt)
{
    tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
    ans[rt]=ans[rt<<1]+ans[rt<<1|1];
}

void pushdown(int l,int r,int rt)
{
    if(flag[rt])
    {
        int m=(l+r)>>1;
        flag[rt<<1]+=flag[rt];
        flag[rt<<1|1]+=flag[rt];
        tree[rt<<1]+=flag[rt];
        tree[rt<<1|1]+=flag[rt];
        flag[rt]=0;
    }
}

void build(int l,int r,int rt)
{
    flag[rt]=0;
    if(l==r)
    {
        tree[rt]=num[l]-1;
        ans[rt]=0;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

void update(int x,int y,int l,int r,int rt)
{
    if(x>r||y<l) return;
    if(x<=l&&r<=y)
    {
        if(tree[rt]>0)
        {
            tree[rt]--;
            flag[rt]--;
        }
        else
        {
            if(l==r) tree[rt]=num[l]-1,ans[rt]++;
            else
            {
                pushdown(l,r,rt);
                int m=(l+r)/2;
                if(tree[rt<<1]==0) update(x,y,lson);
                else
                {
                    flag[rt<<1]--;
                    tree[rt<<1]--;
                }
                if(tree[rt<<1|1]==0) update(x,y,rson);
                else
                {
                    flag[rt<<1|1]--;
                    tree[rt<<1|1]--;
                }
                pushup(rt);
            }
        }
        return;
    }
    pushdown(l,r,rt);
    int m=(l+r)>>1;
    if(x<=m) update(x,y,lson);
    if(m<y) update(x,y,rson);
    pushup(rt);
}

int query(int x,int y,int l,int r,int rt)
{
    if(x>r||y<l) return 0;
    if(x<=l&&r<=y)
    {
        return ans[rt];
    }
    pushdown(l,r,rt);
    int m=(l+r)>>1;
    return query(x,y,lson)+query(x,y,rson);
}

int main()
{
    while(~scanf("%d%d",&n,&q))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
        }
        build(1,n,1);
        for(int i=0;i<q;i++)
        {
            char s[10];
            int l,r;
            scanf("%s",s);
            scanf("%d%d",&l,&r);
            if(strcmp(s,"add")==0) update(l,r,1,n,1);
            else printf("%d\n",query(l,r,1,n,1));
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值