题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6315
学习博客:https://blog.csdn.net/SunMoonVocano/article/details/81207676
Naive Operations
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 502768/502768 K (Java/Others)
Total Submission(s): 4002 Accepted Submission(s): 1773
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⌋
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.
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
Recommend
题目大意:第一行输入n,p 代表数组a[]和b[]的长度为n ,p代表有p次操作,第二行n个数代表b[1]····b[n] 的值 a[1]···a[n]刚开始为0
接下来p行代表p个操作
add l r 表示区间 [l,r]内a数组每个数加一,
query l r 输出区间lr内 ai/bi的值的和(ai/bi向下取整)
思路:自己并不会做这道题,看了别人题解将近花了一天才做出来,感慨自己还是不熟悉线段树 ,一个小问题卡了两个多小时 ,代码中会说我卡在哪了,真的难受,。。。
好了吗,下面真的说思路:
因为ai/bi是向下取整,所以更新ai的值未必会影响到ai/bi的值 ,那么我们怎么进行区间更新呢? 说实话,想了挺久的,也没有想出来,正常思维下 给一个区间里每一个数加上1除以不同的数,那岂不是
要遍历才知道是否超过1,什么情况下可以不用遍历就知道呢? 可以试着猜想一下,如果我们知道那个区间bi的最小值,那么如果区间内最小值都不能提供一个1,那么肯定其它的也是不行的
重点来了: 与其给ai加上1 不如给bi减去一个1 每一次更新,只要bi大于1 那么肯定是对ai/bi没有影响的,所以只要bi-1就行了
具体看代码:
#include<iostream> #include<vector> #include<queue> #include<string.h> #include<cstring> #include<stdio.h> using namespace std; typedef long long ll; const int maxn=1e6+5; const int maxm=1000+5; ll b[maxn<<2];//b数组 ll lazy[maxn<<2];//延迟标记 ll sum[maxn<<2];//记录区间ai/bi的和 ll mi[maxn<<2];//记录b数组区间最小值 ll ans=0; void Pushup(ll rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);//存区间最小的值 } void Build(ll l,ll r,ll rt) { if(l==r) { mi[rt]=b[l]; //cout<<"rt:"<<rt<<"mi:"<<mi[rt]<<endl; return ; } ll mid=(l+r)>>1; Build(l,mid,rt<<1); Build(mid+1,r,rt<<1|1); Pushup(rt); } void Pushdown(ll rt) { mi[rt<<1]-=lazy[rt]; mi[rt<<1|1]-=lazy[rt]; lazy[rt<<1]+=lazy[rt]; lazy[rt<<1|1]+=lazy[rt]; lazy[rt]=0; } void Updata(ll l ,ll r,ll rt,ll L,ll R)//(1,n,1,l,r) { //cout<<"*"<<"l:"<<l<<"r:"<<r<<"L:"<<L<<"R:"<<R<<"mi:"<<mi[rt]<<"rt:"<<rt<<endl; if(L<=l&&r<=R)//这里是重点 { // cout<<"叶子rt:"<<rt<<endl; if(mi[rt]>1)//最小的都大于1,那么整个区间ai/bi肯定是没有影响的, { mi[rt]--; lazy[rt]++; return ; } } if(l==r)//到了叶子节点,代表mi[rt]<=1 此时sum值要加1,同时mi[rt]恢复原值 { sum[rt]++; mi[rt]=b[l]; return ; } if(lazy[rt]) Pushdown(rt); ll mid=(l+r)>>1; if(L<=mid) Updata(l,mid,rt<<1,L,R); if(R>mid) Updata(mid+1,r,rt<<1|1,L,R); Pushup(rt); } void Query(ll l,ll r,ll rt,ll L,ll R) { if(L<=l&&r<=R) { ans+=sum[rt]; return ; } ll mid=(l+r)>>1; if(lazy[rt]) Pushdown(rt); if(L<=mid) Query(l,mid,rt<<1,L,R);//就是这里卡了几个小时 我把l写成1了 !!! 一直re 找了很久。。。 if(R>mid) Query(mid+1,r,rt<<1|1,L,R); } int main() { ll n,q; ll l,r; //string s; char s[10]; //while(cin>>n>>q) while(scanf("%lld%lld",&n,&q)!=EOF)//cin cout会超时 { ans=0; memset(sum,0,sizeof(sum)); memset(lazy,0,sizeof(lazy)); memset(mi,0,sizeof(mi)); for(int i=1;i<=n;i++) scanf("%d",&b[i]); //cin>>b[i]; Build(1,n,1); for(int i=1;i<=q;i++) { ans=0; scanf("%s%lld%lld",s,&l,&r); //cin>>s>>l>>r; if(s[0]=='a') { Updata(1,n,1,l,r); } else { Query(1,n,1,l,r); printf("%lld ",ans); //cout<<ans<<endl; } } } return 0; }