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 思路(dls的):在只有当 ai 加1的次数能够整除 bi 时才会对区间答案有贡献,这样用线段树记录一开始每个点初始化为bi,每次访问的区间有这个点就减1,当为0时表示可以整除bi此位置的贡献加1,然后向下查找初始的bi的值重新赋值,而当查询区间的和时,加上每个点的贡献就行了。大体思路就这样,贴一下标程题解。 这里用树状数组求和的原因是树状数组求和效率更高,代码更短 这个代码复制上去就这样了,可以复制到编译器上调节代码格式看 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<map> #include<vector> #include<set> #include<queue> #include<algorithm> #include<stack> #include<cstdlib> #include<cctype> using namespace std; typedef long long ll; typedef pair<int,int>P; const int INF=0x3f3f3f3f; const int len=1e5+5; ll c[len]; ll b[len]; int n,q; struct Node{ int l,r; ll minx,add;//minx为区间最小值,add为懒标记 int mid(){return (l+r)/2;}//求中位数 }node[len*4]; // //树状数组 void add(int i,ll v) { for(;i<=n;i+=i&-i)c[i]+=v; } ll sum(int i) { ll ans=0; for(;i;i-=i&-i)ans+=c[i]; return ans; } // void pushup(int i) { node[i].minx=min(node[i*2].minx,node[i*2+1].minx); } void built(int i,int l,int r) { node[i].l=l;node[i].r=r; node[i].add=0; if(l==r) { node[i].minx=b[l]; return ; } int mid=node[i].mid(); built(i*2,l,mid); built(i*2+1,mid+1,r); pushup(i); } void pushdown(int i) { if(node[i].add) { node[i*2].minx-=node[i].add; node[i*2+1].minx-=node[i].add; node[i*2].add+=node[i].add; node[i*2+1].add+=node[i].add; node[i].add=0; } } void dfs(int i) { if(node[i].l==node[i].r)//当为叶子节点,跟新 { add(node[i].l,1); node[i].minx=b[node[i].l]; return ; } int ls=i*2,rs=i*2+1; if(node[ls].minx==0)//更新左孩子 { pushdown(ls); dfs(ls); } if(node[rs].minx==0)//更新右孩子 { pushdown(rs);//更新懒标记 dfs(rs); } pushup(i); } void update(int i,int l,int r) { if(l<=node[i].l&&node[i].r<=r)//区间完全包含 { node[i].minx--;//当找到了区间,减一,不会出现为负数的情况,因为区间最小的数减1每次为0,懒标记就更新了 node[i].add++; while(node[i].minx==0) { pushdown(i); dfs(i); } return ; } pushdown(i); int mid=node[i].mid(); if(l<=mid)update(i*2,l,r); if(r>mid)update(i*2+1,l,r); pushup(i); } int main() { while(scanf("%d%d",&n,&q)!=EOF) { memset(c,0,sizeof(c));//初始化数组数组 for(int i=1;i<=n;++i)scanf("%d",b+i); built(1,1,n);//建立线段树 while(q--) { int l,r; char op[10]; scanf("%s%d%d",op,&l,&r); if(op[0]=='a') update(1,l,r);//线段树更新 else printf("%d\n",sum(r)-sum(l-1));//树状数组求和 } } } |