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=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
思路:
设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;
}