HDU 6315-Naive Operations 杭电多校赛1007(线段树区间更新思维好题)

Naive Operations

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

 

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

 

Source

2018 Multi-University Training Contest 2

 

题目大意:给你两个长度为n的数组a、b,数组a初始化为0,数组b存1~n的随机序列

操作1:add x y 给数组a区间为x~y都加1。

操作2:quary x y 查询区间x~y内a[i] / b[i]的和,除法为整除。

解题思路:用线段树来实现区间修改,每个节点初始化为b数组的值,然后再维护区间的最小值,每次执行操作1后,就在线段树中把目标区间的值都减1,当某个区间的最小值为0的时候,就意味着该区间的某个或某些点加到了整除为1的状态,然后就往下查询是哪个点被整除,找到后再把该点的值初始化为原来的b数组的值,并且把结果+1。

我们来分析下此做法的复杂度,因为数组b是1~n的一个排列,每次操作都是把某个区间+1,仔细思考下,有许多点并没有达到能被整除的状态,所以我们可以lazy标记一下,不去更新它,再它达到能被整除的时候才去更新它,这样最坏情况下所有节点更新的次数就为(q+q/2+q/3+q/4+q/5+q/6+q/7+....+q/n)*logn(再乘以线段树区间修改时间),最后的复杂度大概就是q*logn*logn(xjb乱分析的。。)

AC代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>
#include<cstdlib>
#include<stdlib.h>
#include<queue>
#include<map>
#include<set>
#include<stack>
#define bug printf("*********\n");
#define mem0(a) memset(a, 0, sizeof(a));
#define mem1(a) memset(a, -1, sizeof(a));
#define finf(a, n) fill(a, a+n, INF);
#define in1(a) scanf("%d" ,&a);
#define in2(a, b) scanf("%d%d", &a, &b);
#define in3(a, b, c) scanf("%d%d%d", &a, &b, &c);
#define out1(a) printf("%d\n", a);
#define out2(a, b) printf("%d %d\n", a, b);
#define pb(G, b) G.push_back(b);
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<LL, pair<int, LL> > LLppar;
typedef pair<int, int> par;
typedef pair<LL, int> LLpar;
const int mod = 998244353;
const LL INF = 1e9+7;
const int N = 1010;
const double pi = 3.1415926;

int n, m, mi;

struct node
{
    int l;
    int r;
    int num;  //节点当前状态,为0时意味着达到整除状态
    int lazy; //懒惰标记
    int sum; //整除结果
    int b; //b数组初始值
}e[100010*4];

void build(int l, int r, int k)
{
    e[k].l = l;
    e[k].r = r;
    e[k].sum = 0;
    e[k].lazy = 0;
    if(l == r) {
        scanf("%d", &e[k].b);
        e[k].sum = 0;
        e[k].num = e[k].b;
        return;
    }
    int mid = (l+r)/2;
    build(l, mid, 2*k);
    build(mid+1, r, 2*k+1);
    e[k].num = min(e[2*k].num, e[2*k+1].num); //维护区间最小值
}

void push(int k)
{
    if(e[k].lazy) {
        e[2*k].num += e[k].lazy;
        e[2*k+1].num += e[k].lazy;
        e[2*k].lazy += e[k].lazy;
        e[2*k+1].lazy += e[k].lazy;
        e[k].lazy = 0;
    }
}

void update(int l, int r, int k)
{
    if(e[k].l == l && e[k].r == r) {
        e[k].num --;
        if(e[k].num) {
            e[k].lazy --; //该区间没有可以整除的节点
            return;
        }else {
            if(e[k].l == e[k].r) { //找到达到整除状态的节点
                e[k].sum ++;
                e[k].num = e[k].b; //更新
                return;
            }
        }
    }
    push(k);
    int mid = (e[k].l+e[k].r)/2;
    if(r <= mid) update(l, r, 2*k);
    else if(l > mid) update(l, r, 2*k+1);
    else {
        update(l, mid, 2*k);
        update(mid+1, r, 2*k+1);
    }
    e[k].num = min(e[2*k].num, e[2*k+1].num); //维护区间最小值
    e[k].sum = e[2*k].sum + e[2*k+1].sum;
}

int quary(int l, int r, int k)
{
    if(e[k].l == l && e[k].r == r) {
        return e[k].sum;
    }
    int mid = (e[k].l+e[k].r)/2;
    if(r <= mid) return quary(l, r, 2*k);
    else if(l > mid) return quary(l ,r, 2*k+1);
    else {
        return quary(l, mid, 2*k) + quary(mid+1, r, 2*k+1);
    }
}

int main()
{
    char str[10];
    int x, y;
    while(~scanf("%d%d", &n, &m)) {
        build(1, n, 1);
        for(int i = 0; i < m; i ++) {
            scanf("%s%d%d", str, &x, &y);
            if(str[0] == 'a') {
                update(x, y, 1);
            }else printf("%d\n", quary(x, y, 1));
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值