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...aral,al+1...ar
2. query l r: query ∑ri=l⌊ai/bi⌋∑i=lr⌊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≤1000001≤n,q≤100000, 1≤l≤r≤n1≤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
题意 : 有两个长度均为n的数组 刚开始a数组全为0 , b数组人为输入 现在进行两种操作
add l,r, 即给a数组的[l, r ] 区间内的每一个数均加上1
query l, r 询问 ⌊ai/bi⌋的和 ( i 在[l,r] 内);
思路 :设有变量c add , c代表该区间内的最小b值 ,叶子节点的c即为对应的b数组的值 ,add为该区间内共加了多少次1 ,
每加一次1 ,对应区间的add + 1, c -1 , 如果c > 0 则不用向下处理 ,否则c == 0 证明 该区间内有叶子节点sum需要更新将该
节点的add向下传递,则其子节点的c 减对应add 该节点的add值为0 ,以此类推至叶子节点 ,对应叶子节点的c重新为对应的b
add为0 , pushdown , 将该节点的add向下传递,则其子节点的c 减对应add 该节点的add值为0 ,以此类推 ,最后回溯 ,
更新每个节点的sum与c
AC代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
int date[100005];
struct node
{
int add; ///该区间加了几次1
int c ; ///该区间的最小值 每来一次1 c-- r 如果c = 0
int l; ///证明区间有sum值可以被更新
int r;
int sum;
}s[400005];
int build( int i , int a, int b )
{
s[i].l = a;
s[i].r = b;
s[i].sum = 0;
s[i].add = 0;
if( a == b )
{
s[i].c = date[a];
return 1;
}
else
{
int mid = (a+b)/2;
build( 2*i, a, mid );
build( 2*i+1, mid+1, b);
s[i].c = min( s[2*i].c, s[2*i+1].c);
}
}
void pushdown( int i ) ///将add值推下去
{
if( s[i].add )
{
s[2*i].add += s[i].add;
s[2*i+1].add += s[i].add;
s[2*i].c -= s[i].add;
s[2*i+1].c -= s[i].add;
s[i].add = 0;
}
}
void add( int i, int a , int b )
{
if( s[i].l == a && s[i].r == b && s[i].c > 1 )
{
s[i].c--;
s[i].add++;
return ; ///如果该节点区间全部包含在更新范围内 且c > 1 则直接处理 不在向下更新
}
else
if( s[i].l == s[i].r && s[i].c <=1 )
{
s[i].sum++; ///若为叶子节点且c<=1 更新sum c
s[i].add = 0;
s[i].c = date[s[i].l];
return ;
}
else
{ ///向下传递add
pushdown( i );
int mid = ( s[i].l + s[i].r )/2;
if( b <= mid )
{
add( 2*i, a, b);
}
else
if( a > mid )
{
add( 2*i +1, a , b );
}
else
{
add( 2*i, a, mid );
add( 2*i+1, mid+1, b );
}
s[i].sum = s[2*i].sum + s[2*i+1].sum; ///回溯
s[i].c = min( s[2*i].c , s[2*i+1].c );
}
}
int query( int i, int a, int b )
{
if( s[i].l == a && s[i].r == b )
{
return s[i].sum;
}
int mid = ( s[i].l + s[i].r )/2;
if( b <= mid )
{
return query( 2*i, a, b );
}
else
if( a > mid )
{
return query( 2*i+1, a, b );
}
else
{
return query( 2*i, a, mid )+query( 2*i+1, mid+1, b );
}
}
int main()
{
int n, q;
int i , j, k;
char str[10];
int a, b;
while( scanf("%d%d", &n, &q) != EOF )
{
memset( date, 0, sizeof( date ));
memset( s, 0 , sizeof( s ));
for( i = 1; i<=n; i++)
{
scanf("%d", &date[i]);
}
build( 1, 1 , n );
for( i = 0; i<q; i++)
{
scanf("%s", str );
//printf("%s\n", str);
scanf("%d%d", &a, &b);
if( str[0] == 'a')
{
add( 1, a, b );
}
else
if( str[0] == 'q')
{
int ans = query( 1, a, b );
printf("%d\n", ans);
}
memset( str, 0, sizeof( str ));
}
}
return 0;
}