LibreOJ 6277,6278,6280 数列分块入门1,2,4 树状数组,分块,线段树等.

模板一共有九个.我试着在三天内做了3个.
应该不用超链接吧.

分块1

区间加,单点询问.
这不是裸的改版树状数组吗?用树状数组处理前缀和水过.

#include<bits/stdc++.h>
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
inline int read(){
  re0 x=0,f=1;rec c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=x*10+c-'0';
  return x*(f?1:-1);
  }
inline void read(rel &x){
  x=0;re0 f=1;rec c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=x*10+c-'0';
  x*=f?1:-1;
  }
inline int write(rel x){
  if (!x) return pc(48);
  if (x<0) x=-x,pc('-');
  re0 bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  }
}
using namespace chtholly;
using namespace std;
#define lowbit(x) (x&-x)
const int karen=5e5;
int n=read();
ll a[karen|10],c[karen|10];
inline void add(int x,int k){for (;x<=n;x+=lowbit(x)) c[x]+=k;}
inline int query(int x){int sum=0;for (;x>0;x-=lowbit(x)) sum+=c[x];return sum;}

int main()
{
re0 i;
for (i=1;i<=n;++i) a[i]=read();
for (i=1;i<=n;++i)
  {
  re0 k=read(),x=read(),y=read(),z=read();
  if (!k) add(x,z),add(y+1,-z);
  else write(a[y]+query(y)),pl;
  }
}

分块2

区间加,区间查询小于c^2的数的个数.
好题.线段树是搞不定的,考虑玄学分块.
数组开了5e4,莫名RE30分.我开成了1e5,A掉了.我不知道怎么回事.

/*
分块处理.
对于修改,左右两个不包含整块的部分,我们就暴力修改并重构整个块.
中间的整块的部分我们维护一个延迟标记,询问的时候减去标记即可.
至于询问,左右两个部分暴力扫一下,中间对每一块进行二分求出答案.
我写的分块实在丑了点.
*/
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
inline int read(){
  re0 x=0,f=1;rec c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=x*10+c-'0';
  return x*(f?1:-1);
  }
inline void read(rel &x){
  x=0;re0 f=1;rec c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=x*10+c-'0';
  x*=f?1:-1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return pc(48);
  if (x<0) x=-x,pc('-');
  re0 bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  }
}
using namespace chtholly;
using namespace std;
#define belong(x) (((x)-1)/block+1)//这个位置所属的块.
#define all(u) v[u].begin(),v[u].end() 
const int karen=1e5;
typedef int fuko[karen|10];//定义了fuko类型是大小为karen+10的数组.
fuko a,l,r,lazy;
int n=read(),block,num;
vector<int> v[karen|10];
/*
block是每一块的大小,num是一共的块数. 
l,r分别是每一块的左边界和右边界,belong是每一个位置所属的块. 
lazy是给某一块的所有数加上的值.(询问的时候用c减去就可以了.) 
*/

void buildblock()//预处理每个块的信息.
{
re0 i;
block=sqrt(n),num=n/block+n%block;
for (i=1;i<=num;++i) l[i]=(i-1)*block+1,r[i]=i*block;r[num]=n;//处理每个块的左边界和右边界.注意特判最后一块的右边界是n.
for (i=1;i<=n;++i) v[belong(i)].push_back(a[i]);//vector从小到大存放每一个块内的数.
for (i=1;i<=num;++i) sort(all(i));
}

void readd(int x)//直接重构块.
{
v[x].clear();
for (re0 i=l[x];i<=r[x];++i)
  v[x].push_back(a[i]);
sort(all(x));
}

void update(int ql,int qr,int k)//区间修改.
{
re0 i;
for (i=ql;i<=min(r[belong(ql)],qr);++i)//暴力扫从l到它所在块右边界的部分.
  a[i]+=k;
readd(belong(ql));
if (belong(ql)!=belong(qr))//如果l和r不在同一块内,处理r所在的部分.
  {
  for (i=l[belong(qr)];i<=qr;++i)
    a[i]+=k;
  readd(belong(qr));
  }
for (i=belong(ql)+1;i<belong(qr);++i) 
  lazy[i]+=k;//处理一下延迟标记.
}

int query(int ql,int qr,int c)
{
re0 ans=0,i;
for (i=ql;i<=min(qr,r[belong(ql)]);++i)
  ans+=a[i]+lazy[belong(i)]<c;//暴力 
if (belong(ql)!=belong(qr)) 
  {
  for (i=l[belong(qr)];i<=qr;++i) 
    ans+=a[i]+lazy[belong(i)]<c;//暴力
  }
for (i=belong(ql)+1;i<belong(qr);++i)
  ans+=lower_bound(all(i),c-lazy[i])-v[i].begin();//二分求每一个块的答案.
return ans;
}

int main()
{
re0 i;
for (i=1;i<=n;++i) a[i]=read();
buildblock();
for (i=1;i<=n;++i)
  {
  re0 op=read(),l=read(),r=read(),k=read();
  if (op) write(query(l,r,k*k)),pl;
  else update(l,r,k);
  }
}

分块4

区间加,区间求和.
这个显然是线段树,不用说了.

#include<bits/stdc++.h>
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
inline int read(){
  re0 x=0,f=1;rec c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=x*10+c-'0';
  return x*(f?1:-1);
  }
inline void read(rel &x){
  x=0;re0 f=1;rec c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=x*10+c-'0';
  x*=f?1:-1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return pc(48);
  if (x<0) x=-x,pc('-');
  re0 bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  }
}
using namespace chtholly;
using namespace std;
const int karen=5e4;
typedef ll fuko[karen<<2];
int n=read();

struct segtree{
#define le rt<<1
#define ri le|1
#define ls le,l,mid
#define rs ri,mid+1,r
fuko val,lazy;
void build(int rt,int l,int r){
  if (l==r) val[rt]=read();
  else{
    int mid=l+r>>1;
    build(ls),build(rs);
    val[rt]=val[le]+val[ri];
    }
  }
void push_down(int rt,int l,int r){
  if (lazy[rt]){
    int mid=l+r>>1;
    lazy[le]+=lazy[rt],lazy[ri]+=lazy[rt];
    val[le]+=(mid-l+1)*lazy[rt],val[ri]+=(r-mid)*lazy[rt];
    lazy[rt]=0;
    }
  }
void update(int rt,int l,int r,int ql,int qr,int v){
  if (ql>r||qr<l) return;
  if (ql<=l&&qr>=r){
    val[rt]+=1ll*(r-l+1)*v;
    lazy[rt]+=v;
    } 
  else{
    int mid=l+r>>1;
    push_down(rt,l,r);
    update(ls,ql,qr,v),update(rs,ql,qr,v);
    val[rt]=val[le]+val[ri];
    }
  }
ll query(int rt,int l,int r,int ql,int qr){
  if (ql>r||qr<l) return 0;
  if (ql<=l&&qr>=r) return val[rt];
  int mid=l+r>>1;
  push_down(rt,l,r);
  return query(ls,ql,qr)+query(rs,ql,qr);
  }
}my_;

int main()
{
my_.build(1,1,n);
for (re0 i=1;i<=n;++i)
  {
  re0 t=read(),l=read(),r=read(),k=read();
  if (t) write((my_.query(1,1,n,l,r)%(k+1)+k+1)%(k+1)),pl;
  else my_.update(1,1,n,l,r,k);
  }
}

Thank you.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值