数列分块入门1
传送门
数列分块 就是把一个数组分成一块一块的每个块的大小为sqrt(n) 对于每次对元素的查询修改 可以直接对它所在的块操作 可以节省很多时间
//乱七八糟的维护区间的 用分块去做
//分了根号n块 复杂度为根号n
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
long long belong[maxn],block,l[maxn],r[maxn],num=0;
long long n;
long long a[maxn];
long long add[maxn];
void build()
{
block=sqrt(n);//块的大小
num=n/block;if(n%block)num++;//块的个数
for(int i=1;i<=num;i++)
{
l[i]=(i-1)*block+1;
r[i]=i*block;//每一个块的左右边界
}
r[num]=n;
for(int i=1;i<=n;i++)
belong[i]=(i-1)/block+1;//每个元素属于哪个块
}
void update(long long x,long long y,long long z)
{
if(belong[x]==belong[y])
{
for(int i=x;i<=y;i++)
a[i]+=z;
}
else
{
for(int i=belong[x]+1;i<=belong[y]-1;i++)//对包括在x到y之间的整数块进行操作
add[i]+=z;
for(int i=x;i<=r[belong[x]];i++)如果x y之间有不是在整数块内的 对其单独操作即可
a[i]+=z;
for(int i=l[belong[y]];i<=y;i++)
a[i]+=z;
}
}
//long long ask(int x,int y)
//{
// long long ans=0;
// if(belong[x]==belong[y])
// {
// for(int i=x;i<=y;i++)
// ans=max(ans,a[i]);
// return ans;
// }
// for(int i=x;i<=r[belong[x]];i++)
// {
// ans=max(ans,a[i]);
// }
// for(int i=belong[x]+1;i<belong[y];i++)
// ans=max(ans,Max[i]);
// for(int i=l[belong[y]];i<=y;i++)
// ans=max(ans,a[i]);
// return ans;
//}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
build();
for(int i=1;i<=n;i++)
{
int op,l,r,w;
cin>>op>>l>>r>>w;
if(op==0)
update(l,r,w);
else
cout<<a[r]+add[belong[r]]<<endl;//add标记的是对块操作的值
}
}
数列分块入门2
传送门
这次问的不是某个点的值了,题目问的是l r 区间有多少个元素小于等于cc
看了dalao的写法 将每个块内的元素用vector存起来 并且从小到大排序 如果有更新到某个块内的元素 我们就将这个块所在的vector重新存 再排序 求解每个整块内有几个小于cc的时候我们之间用lower_bound即可
//我看过你说想要时间停止 拉着我的手喊我名字
//这道题困扰了我好久 有些变量搞错了 做题一定要细心啊!
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
typedef long long ll;
ll a[5*maxn],l[5*maxn],r[5*maxn],belong[5*maxn],block,num;
ll n,tag[5*maxn];
vector<int>v[10001];
void build()
{
block=sqrt(n);//依然是每个块的大小
num=n/block;//有几个块
if(n%block)//多出来的也要存到末尾块里 块树加一
num++;
for(int i=1; i<=n; i++)
{
belong[i]=(i-1)/block+1;//每个元素属于哪个块
v[belong[i]].push_back(a[i]);//将属于这个块的元素都存到vector中去
}
r[num]=n;//防止越界嘛
for(int i=1; i<=num; i++)
{
l[i]=(i-1)*block;//每个块的边界 这里也困扰到我了 实际上 r[i-1]=l[i] 在计算的时候 不能重复计算进去
r[i]=i*block;
sort(v[i].begin(),v[i].end());
}
}
void update(int x)//这里的x我传进来的是块下标 而不是元素下标
{
v[x].clear();//当前块内的元素被更新 要对它的vector也更新一下!
for(int i=l[x]+1;i<=r[x];i++)//将属于当前块的元素都重新放进去 为什么从l[x]+1开始 因为l[x]=r[x-1] 下面的 +1 同理
v[x].push_back(a[i]);
sort(v[x].begin(),v[x].end());//再次排序
}
void add(long long x,long long y,long long c)
{
//可以分为三个部分 1、x到x所在块的右边界 2、x右边界到y左边界中间的整块 3、 y的左边界到y
for(int i=x;i<=min(r[belong[x]],y);i++) a[i]+=c;
// 部分1 如果x和y在一个块内 那这个块中并不是所有的元素都被更新了 只有x到y 此时y<=r[belong[x]]
//如果x y不在一个块内 我们只需要更新不在整块内的元素即可 在整块的区间直接对块操作 此时y>r[belong[x]]
update(belong[x]);//x所在的块中元素被更新 其对应vector也要更新
if(belong[x]!=belong[y])// 部分2 x y不在一个块内的情况 需要对y所在的块处理一下
{
for(int i=l[belong[y]]+1;i<=y;i++)
a[i]+=c;
update(belong[y]);
}
for(int i=belong[x]+1;i<=belong[y]-1;i++)//部分3 x y区间中整块的部分 直接对块操作
tag[i]+=c;
}
long long getsum(long long x,long long y,long long c)
{//这里跟上面是一样的
long long ans=0;
for(int i=x;i<=min(r[belong[x]],y);i++)
{
if(a[i]+tag[belong[x]]<c)
ans++;
}
if(belong[x]!=belong[y])
{
for(int i=l[belong[y]]+1;i<=y;i++)//
if(a[i]+tag[belong[y]]<c)
ans++;
}
for(int i=belong[x]+1;i<=belong[y]-1;i++)
{
int t=c-tag[i];
ans+=lower_bound(v[i].begin(),v[i].end(),t)-v[i].begin();
}
return ans;
}
int main()
{
int i,op,l,r,c;
cin>>n;
for(i=1; i<=n; i++)
cin>>a[i];
build();
for(i=1; i<=n; i++)
{
cin>>op>>l>>r>>c;
if(op==0)
add(l,r,c);
else
{
cout<<getsum(l,r,c*c)<<endl;
}
}
}
/*
4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2
*/
牛客
昨天比赛的时候一看这道题就想到了分块 但是还是没写对 刚刚看了过了90%
改了一处过了
这道题问的是l r区间内是不是单调递增的
老样子 哪个块修改了 就去更新这个块 tag标记这个块是不是完美的 不是完美的标记为1 完美的标记为2 另外需要注意的是 块与块之间也要是完美的 只需要判断 两个块衔接的端点处就可以了 看见别人有用c++函数做的 很简单用is_sorted(l,r)如果l r区间内是升序的返回1 否则返回0 还有用线段树啥的做的 都可以吧 但是我仍然选择我新学的分块
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
long long n,block,r[maxn*3],l[maxn*3],num,belong[maxn*3];
long long a[maxn*3],tag[maxn*3];
void build()
{
for(int i=1; i<=num; i++)
{
l[i]=(i-1)*block;
r[i]=i*block;
for(int j=l[i]+1; j<=r[i]&&j<=n; j++)
{
if(a[j]>=a[j-1])
continue;
tag[i]=1;
break;
}
}
r[num]=n;
}
void update(long long x,long long y)
{
a[x]=y;
for(int i=l[belong[x]]+1; i<=r[belong[x]]; i++)
{
if(a[i]>=a[i-1])
continue;
else
{
tag[belong[x]]=1;
return ;
}
}
tag[belong[x]]=0;
return ;
}
int query(long long x,long long y)
{
if(belong[x]==belong[y])
{
for(int i=x+1;i<=y;i++)
{
if(a[i]>=a[i-1])
continue;
else
return 0;
}
return 1;
}
for(int i=belong[x]+1; i<=belong[y]-1; i++)
{
if(tag[i])
{
return 0;
}
if(a[r[i]]<=a[r[i]+1])
continue;
else
return 0;
}
for(int i=x+1;i<=r[belong[x]]+1;i++)
{
if(a[i]>=a[i-1])
continue;
else
return 0;
}
for(int i=l[belong[y]]+1;i<=y;i++)
{
if(a[i]>=a[i-1])
continue;
else
return 0;
}
return 1;
}
int main()
{
int i,j,m;
cin>>n>>m;
block=sqrt(n);
num=n/block;
if(n%block)
num++;
for(i=1; i<=n; i++)
{
cin>>a[i];
belong[i]=(i-1)/block+1;
}
build();
for(i=1; i<=m; i++)
{
long long op,l,r;
cin>>op>>l>>r;
if(op==1)
{
update(l,r);
}
else
{
if(l==r||n==1)
{
printf("Yes\n");
continue;
}
if(query(l,r))
printf("Yes\n");
else
printf("No\n");
}
}
return 0;
}