众所周知分块是一种非常优秀的暴力算法
T1 把我吊打(我生气了所以不想写这道题的题解)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define ll long long
using namespace std;
ll n,l[50010],r[50010],sqrtn,op,ql,qr,c;
ll num[50010],pos[50010],sum[50010];
ll read()
{
ll x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void add(ll st,ll ed,ll addd)
{
if(pos[st]==pos[ed])
{
for(ll i=st;i<=ed;i++)
num[i]+=addd;
return ;
}
for(ll i=st;i<=r[pos[st]];i++)
num[i]+=addd;
for(ll i=pos[st]+1;r[i]<=ed && i<=sqrtn;i++)
sum[i]+=addd;
if(ed!=r[pos[ed]])
{
for(ll i=l[pos[ed]];i<=ed;i++)
num[i]+=addd;
}
}
int main()
{
// freopen("fenkuai.in","r",stdin);
// freopen("own.out","w",stdout);
n=read();
sqrtn=sqrt(n);
for(ll i=1;i<=n;i++)
num[i]=read();
for(ll i=1;i<=sqrtn;i++)
{
l[i]=(i-1)*sqrtn+1;
r[i]=i*sqrtn;
}
if(r[sqrtn]<n)
{
sqrtn++;
l[sqrtn]=r[sqrtn-1]+1;
r[sqrtn]=n;
}
for(ll i=1;i<=sqrtn;i++)
for(ll j=l[i];j<=r[i];j++)
pos[j]=i;
for(ll i=1;i<=n;i++)
{
op=read();ql=read();qr=read();c=read();
if(op==0)
add(ql,qr,c);
else
printf("%lld\n",num[qr]+sum[pos[qr]]);
}
return 0;
}
T2
其实就是一道在每个块内性感排序的题
修改操作就是在原数组修改了后,把块清零然后重新加入数据然后排序
如果当前块整体修改,就不要进行上面的操作,用tag数组标记一下就ojbk了
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=100010;
int bl[maxn],sqrtn;
int n,a[maxn],tag[maxn];
vector<int> x[maxn];
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void deletandreturn(int u)
{
x[u].clear();
for(int i=(u-1)*sqrtn+1;i<=min(u*sqrtn,n);i++)
x[u].push_back(a[i]);
sort(x[u].begin(),x[u].end());
}
void add(int l,int r,int c)
{
for(int i=l;i<=min(bl[l]*sqrtn,r);i++)
a[i]+=c;
deletandreturn(bl[l]);
if(bl[l]!=bl[r])
{
for(int i=(bl[r]-1)*sqrtn+1;i<=r;i++)
a[i]+=c;
deletandreturn(bl[r]);
}
for(int i=bl[l]+1;i<=bl[r]-1;i++)
tag[i]+=c;
}
int query(int l,int r,int c)
{
int ans=0;
for(int i=l;i<=min(bl[l]*sqrtn,r);i++)
if(a[i]+tag[bl[l]]<c)
ans++;
if(bl[l]!=bl[r])
{
for(int i=(bl[r]-1)*sqrtn+1;i<=r;i++)
if(a[i]+tag[bl[r]]<c)
ans++;
}
for(int i=bl[l]+1;i<=bl[r]-1;i++)
{
int cxknmsl=c-tag[i];
ans+=lower_bound(x[i].begin(),x[i].end(),cxknmsl)-x[i].begin();//lowerbound是找第一个小于等于cxknmsl的,但是因为下标是从0开始,所以返回的是前驱的值
}
return ans;
}
int main()
{
// freopen("fenkuai.in","r",stdin);
// freopen("own.out","w",stdout);
n=read();
sqrtn=sqrt(n);
for(int i=1;i<=n;i++)
{
a[i]=read();
bl[i]=(i-1)/sqrtn+1;
}
for(int i=1;i<=n;i++)
x[bl[i]].push_back(a[i]);
for(int i=1;i<=bl[n];i++)
sort(x[i].begin(),x[i].end());
for(int i=1;i<=n;i++)
{
int op,l,r,c;
op=read();l=read();r=read();c=read();
if(op==0)
add(l,r,c);
else
printf("%d\n",query(l,r,c*c));
}
return 0;
}
T3
和T2好像没什么区别,反正用lower_bound找到就行了
注意特判lower_bound的返回值一定是在块内 否则continue
因为用的是vector 下表是从0开始的 应该注意一下
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=100010;
int bl[maxn],sqrtn;
int n,a[maxn],tag[maxn];
vector<int> x[maxn];
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void deletandreturn(int u)
{
x[u].clear();