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=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
【题目链接】 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;
}