[学习笔记]数列分块入门1-3
Owen_codeisking · · 个人记录
数列分块入门 1
题目描述:
给出一个长为
输入格式:
第一行输入一个数字
第二行输入
接下来输入
若
若
输出格式:
对于每次询问,输出一行一个数字表示答案。
样例输入:
4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0
样例输出:
2
5
提示:
对于
时间限制:
空间限制:
分析
其实就是数列分块入门
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n,t;
ll a[100010],sum[1010],add[1010];
ll L[1010],R[1010],pos[100010];
void change(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
for(ll i=l;i<=r;i++) a[i]+=d;
sum[p]+=d*(r-l+1);
}
else {
for(ll i=p+1;i<=q-1;i++) add[i]+=d;
for(ll i=l;i<=R[p];i++) a[i]+=d;
sum[p]+=d*(R[p]-l+1);
for(ll i=L[q];i<=r;i++) a[i]+=d;
sum[q]+=d*(r-L[q]+1);
}
}
ll ask(ll l){
ll p=pos[l];
return add[p]+a[l];
}
int main()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
scanf("%lld",&a[i]);
t=sqrt(n);
for(ll i=1;i<=t;i++){
L[i]=(i-1)*t+1,R[i]=i*t;
}
if(R[t]!=n) t++,L[t]=R[t-1]+1,R[t]=n;
for(ll i=1;i<=t;i++){
for(ll j=L[i];j<=R[i];j++){
pos[j]=i;
}
}
for(ll i=1;i<=n;i++){
ll e,l,r,k;
scanf("%lld%lld%lld%lld",&e,&l,&r,&k);
if(e==0) {
change(l,r,k);
}
else printf("%lld\n",ask(r));
}
return 0;
}
数列分块入门 2(教主的魔法)
题目描述:
给出一个长为
输入格式:
第一行输入一个数字
第二行输入
接下来输入
若
若
输出格式:
对于每次询问,输出一行一个数字表示答案。
样例输入:
4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2
样例输出:
3
0
2
提示:
对于
分析
好题。
这道题看到
1、在一段内就暴力枚举,用
2、否则不在一段内:
(1)不完整一段重复
(2)否则在排序完了的
时间复杂度
时间限制:
空间限制:
#include <bits/stdc++.h>
#define ll long long
#define maxn 50010
#define maxm 310
using namespace std;
ll n,t;
ll a[maxn],add[maxm],b[maxn];
ll pos[maxn],L[maxm],R[maxm];
void change(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
for(int i=l;i<=r;i++) a[i]+=d;
for(int i=L[p];i<=R[p];i++) b[i]=a[i];
sort(b+L[p],b+R[p]+1);
}
else {
for(int i=p+1;i<=q-1;i++) add[i]+=d;
for(int i=l;i<=R[p];i++) a[i]+=d;
for(int i=L[p];i<=R[p];i++) b[i]=a[i];
sort(b+L[p],b+R[p]+1);
for(int i=L[q];i<=r;i++) a[i]+=d;
for(int i=L[q];i<=R[q];i++) b[i]=a[i];
sort(b+L[q],b+R[q]+1);
}
}
ll query(ll l,ll r,ll d){
ll x=lower_bound(b+l,b+r+1,d)-b;
//printf("%lld %lld %lld %lld\n",l,r,d,x-l);
return x-l;
}
ll ask(ll l,ll r,ll d){
ll p=pos[l],q=pos[r],ans=0;
if(p==q){
for(int i=l;i<=r;i++)
if(d-add[p]>a[i])
ans++;
}
else {
for(int i=p+1;i<=q-1;i++)
ans+=query(L[i],R[i],d-add[i]);
for(int i=l;i<=R[p];i++)
if(d-add[p]>a[i])
ans++;
for(int i=L[q];i<=r;i++)
if(d-add[q]>a[i])
ans++;
}
return ans;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
t=sqrt(n);
for(int i=1;i<=t;i++)
L[i]=(i-1)*t+1,R[i]=i*t;
if(R[t]!=n) t++,L[t]=R[t-1]+1,R[t]=n;
for(int i=1;i<=t;i++){
for(int j=L[i];j<=R[i];j++){
pos[j]=i;b[j]=a[j];
}
sort(b+L[i],b+R[i]+1);
}
/*for(int i=1;i<=n;i++)
printf("%d ",pos[i]);
printf("\n");*/
for(int i=1;i<=n;i++){
ll k,l,r,c;
scanf("%lld%lld%lld%lld",&k,&l,&r,&c);
if(k==0){
change(l,r,c);
}
else {
printf("%lld\n",ask(l,r,c*c));
}
/*for(int i=1;i<=n;i++)
printf("%d ",a[i]);
printf("\n");
for(int i=1;i<=n;i++)
printf("%d ",b[i]);
printf("\n");
for(int i=1;i<=t;i++)
printf("%d ",add[i]);
printf("\n");*/
}
return 0;
}
数列分块入门 3
题目描述:
给出一个长为
输入格式:
第一行输入一个数字
第二行输入
接下来输入
若
若
输出格式:
对于每次询问,输出一行一个数字表示答案。
样例输入:
4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4
样例输出:
3
-1
提示:
对于
分析
跟上题差不多,但时间小了一半,
时间限制:
空间限制:
#include <bits/stdc++.h>
#define ll int
#define maxn 100010
#define maxm 1010
using namespace std;
ll n,t;
ll a[maxn],add[maxm],b[maxn];
ll pos[maxn],L[maxm],R[maxm];
void change(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
for(ll i=l;i<=r;i++) a[i]+=d;
for(ll i=L[p];i<=R[p];i++) b[i]=a[i];
sort(b+L[p],b+R[p]+1);
}
else {
for(ll i=p+1;i<=q-1;i++) add[i]+=d;
for(ll i=l;i<=R[p];i++) a[i]+=d;
for(ll i=L[p];i<=R[p];i++) b[i]=a[i];
sort(b+L[p],b+R[p]+1);
for(ll i=L[q];i<=r;i++) a[i]+=d;
for(ll i=L[q];i<=R[q];i++) b[i]=a[i];
sort(b+L[q],b+R[q]+1);
}
}
ll query(ll l,ll r,ll d){
ll x=lower_bound(b+l,b+r+1,d)-b;
//printf("%lld %lld %lld %lld\n",l,r,d,x-l);
return x-1;
}
ll ask(ll l,ll r,ll d){
ll p=pos[l],q=pos[r],ans=-999999;
if(p==q){
for(ll i=l;i<=r;i++)
if(d>a[i]+add[p])
ans=max(ans,a[i]+add[p]);
}
else {
for(ll i=p+1;i<=q-1;i++){
ll v=query(L[i],R[i],d-add[i]);
if(d>b[v]+add[i])
ans=max(ans,b[v]+add[i]);
}
for(ll i=l;i<=R[p];i++)
if(d>a[i]+add[p])
ans=max(ans,a[i]+add[p]);
for(ll i=L[q];i<=r;i++)
if(d>a[i]+add[q])
ans=max(ans,a[i]+add[q]);
}
return ans;
}
int main()
{
scanf("%d",&n);
for(ll i=1;i<=n;i++)
scanf("%d",&a[i]);
t=sqrt(n);
for(ll i=1;i<=t;i++)
L[i]=(i-1)*t+1,R[i]=i*t;
if(R[t]!=n) t++,L[t]=R[t-1]+1,R[t]=n;
for(ll i=1;i<=t;i++){
for(ll j=L[i];j<=R[i];j++){
pos[j]=i;b[j]=a[j];
}
sort(b+L[i],b+R[i]+1);
}
/*for(int i=1;i<=n;i++)
printf("%d ",pos[i]);
printf("\n");*/
for(ll i=1;i<=n;i++){
ll k,l,r,c;
scanf("%d%d%d%d",&k,&l,&r,&c);
if(k==0){
change(l,r,c);
}
else {
ll ans=ask(l,r,c);
if(ans!=-999999)
printf("%d\n",ans);
else printf("-1\n");
}
/*for(int i=1;i<=n;i++)
printf("%d ",a[i]);
printf("\n");
for(int i=1;i<=n;i++)
printf("%d ",b[i]);
printf("\n");
for(int i=1;i<=t;i++)
printf("%d ",add[i]);
printf("\n");*/
}
return 0;
}