2018 Multi-University Training Contest 2 1007
Naive Operations
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 502768/502768 K (Java/Others)
Total Submission(s): 1103 Accepted Submission(s): 450
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=l⌊ai/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≤l≤r≤n, 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
题意:有一个数组a[] 初始值全为0,还有一个静态数组b[],里面的值是 1 - n 不重复的
对数组a做线段树的操作,唯一不同的是查询操作
它在查询的时候要求 区间 [l,r] 里所有值 / b[i] 的值 (整数相除,不带小数)
思路:
首先题目的关键是 b数组是 1-n不重复的,那么也就是说,我对 a 数组做了再多的操作,能够使得最后 a[i] / b[i] 的值发生改变的并不多,因为 n 最大是 100000,所以 b[i] 最大是 100000,而我操作次数最多也就是 100000,所以极限情况下,数组长度为 100000,我做100000次更新操作,每次都更新 [1,100000]的区间,那么 [50001,100000] 区间里的 a[i] / b[i] 结果才只会被改变一次,这是一个 logn 级别的更新频率,所以我们要维护的就是 a[i] / b[i] 的值,且叶子节点的更新次数并不会特别多,所以时间复杂度是足够的。
但是对于线段树而言,维护的值可以有多个,那么我们维护一个区间被更新的最大次数 maxA,和使得 a[i] / b[i] 的值发生改变所需要花费更新次数的最小值 minB,那么当我们更新到了叶子节点的时候,如果 maxA > minB,那就意味着 a[i] / b[i] 发生了变化,我们用 sum 记录 a[i] / b[i] 的值,这个时候 sum ++ ,然后我们让 minB += b[i] ,这样就能判断下次的 a[i] / b[i] 发生变化
用 lazy 懒惰更新 minA,区间维护 maxA,minB,sum,最后查询的时候查询 sum 即可
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define mem(a,x) memset(a,x,sizeof(a))
const int maxn = 100005;
struct node{
int l,r,maxA,minB,sum,lazy;
}tree[maxn * 4];
int b[maxn];
void push_up(int rt){
tree[rt].minB = min(tree[rt << 1].minB,tree[rt << 1 | 1].minB);
tree[rt].maxA = max(tree[rt << 1].maxA,tree[rt << 1 | 1].maxA);
tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
}
void push_down(int rt){
if(tree[rt].lazy){
tree[rt << 1].lazy += tree[rt].lazy;
tree[rt << 1 | 1].lazy += tree[rt].lazy;
tree[rt << 1].maxA += tree[rt].lazy;
tree[rt << 1 | 1].maxA += tree[rt].lazy;
tree[rt].lazy = 0;
}
}
void build_tree(int l,int r,int rt){
tree[rt].l = l;
tree[rt].r = r;
tree[rt].lazy = 0;
if(l == r){
tree[rt].minB = b[l];
tree[rt].sum = 0;
tree[rt].maxA = 0;
return;
}
int mid = (l + r) >> 1;
build_tree(l,mid,rt << 1);
build_tree(mid + 1,r,rt << 1 | 1);
push_up(rt);
}
void update_interval(int l,int r,int rt){
if(l <= tree[rt].l && r >= tree[rt].r){
tree[rt].maxA++;
if(tree[rt].maxA < tree[rt].minB){
tree[rt].lazy++;
return;
}
if(tree[rt].l == tree[rt].r && tree[rt].maxA >= tree[rt].minB){
tree[rt].sum++;
tree[rt].minB += b[tree[rt].l];
return;
}
}
push_down(rt);
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(l <= mid){
update_interval(l,r,rt << 1);
}
if(r > mid){
update_interval(l,r,rt << 1 | 1);
}
push_up(rt);
}
int query_interval(int l,int r,int rt){
if(l <= tree[rt].l && r >= tree[rt].r)
return tree[rt].sum;
push_down(rt);
int ans = 0;
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(l <= mid){
ans += query_interval(l,r,rt << 1);
}
if(r > mid){
ans += query_interval(l,r,rt << 1 | 1);
}
return ans;
}
int main(){
int n,m,l,r;
char opt[10];
while(scanf("%d %d",&n,&m) != EOF){
for(int i = 1;i <= n;i++){
scanf("%d",&b[i]);
}
build_tree(1,n,1);
while(m--){
scanf("%s %d %d",opt,&l,&r);
if(opt[0] == 'a'){
update_interval(l,r,1);
}else{
printf("%d\n",query_interval(l,r,1));
}
}
}
return 0;
}