hzwer分块九题(暂时持续更新)

hzwer分块9题

分块1:区间加法,单点查询

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
using namespace std;
const int N=5e5+10,inf=2e9;
int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
    return ans*f;
}
int n,m,block;
int pos[N],v[N],tag[N];

void add(int a,int b,int c) {
    for(int i=a;i<=min(pos[a]*block,b);i++) v[i]+=c;
    if(pos[a]!=pos[b])
        for(int i=(pos[b]-1)*block+1;i<=b;i++) v[i]+=c;
    for(int i=pos[a]+1;i<=pos[b]-1;i++) tag[i]+=c;
}

int main()
{
    in(n); block=sqrt(n);
    for(int i=1;i<=n;i++) in(v[i]);
    for(int i=1;i<=n;i++)
        pos[i]=(i-1)/block+1;
    for(int i=1;i<=n;i++) {
        int op,a,b,c;
        in(op),in(a),in(b),in(c);
        if(!op) add(a,b,c);
        else cout<<v[b]+tag[pos[b]]<<endl;//a,c没用
    }
}

分块2:区间加法,求区间内小于x的个数
提示:暴力+二分,但是由于一些数加了之后会改变顺序,所以要重构

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
using namespace std;
const int N=5e5+10,inf=2e9;
int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
    return ans*f;
}
int n,m,block;
int pos[N],v[N],tag[N];
vector<int>t[N];

void rebuild(int x) {
    t[x].clear();
    for(int i=(x-1)*block+1;i<=min(n,x*block);i++)
        t[x].push_back(v[i]);
    sort(t[x].begin(),t[x].end());
}

void add(int a,int b,int c) {
    for(int i=a;i<=min(pos[a]*block,b);i++) v[i]+=c;
    rebuild(pos[a]);
    if(pos[a]!=pos[b]) {
        for(int i=(pos[b]-1)*block+1;i<=b;i++) v[i]+=c;
        rebuild(pos[b]);
    }
    for(int i=pos[a]+1;i<=pos[b]-1;i++) tag[i]+=c;
}

int query(int a,int b,int c,int ans=0) {
    for(int i=a;i<=min(pos[a]*block,b);i++)
        if(v[i]+tag[pos[a]]<c) ans++;
    if(pos[a]!=pos[b])
        for(int i=(pos[b]-1)*block+1;i<=b;i++)
            if(v[i]+tag[pos[b]]<c) ans++;
    for(int i=pos[a]+1;i<=pos[b]-1;i++) {
        int x=c-tag[i];
        ans+=lower_bound(t[i].begin(),t[i].end(),x)-t[i].begin();
    }return ans;
}

int main()
{
    in(n); block=sqrt(n);
    for(int i=1;i<=n;i++) in(v[i]);
    for(int i=1;i<=n;i++) {
        pos[i]=(i-1)/block+1;
        t[pos[i]].push_back(v[i]);
    }
    for(int i=1;i<=pos[n];i++) sort(t[i].begin(),t[i].end());
    for(int i=1;i<=n;i++) {
        int op,a,b,c;
        in(op),in(a),in(b),in(c);
        if(!op) add(a,b,c);
        else cout<<query(a,b,c*c)<<endl;
    }
}

分块3:区间加法,求前驱
提示:暴力+二分(set)

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
using namespace std;
const int N=5e5+10,inf=2e9;
int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
    return ans*f;
}
int n,m,block;
int pos[N],v[N],tag[N];
set<int>s[N];

void add(int a,int b,int c) {
    for(int i=a;i<=min(pos[a]*block,b);i++) {
        s[pos[a]].erase(v[i]);
        s[pos[a]].insert(v[i]+=c);
    }
    if(pos[a]!=pos[b]) {
        for(int i=(pos[b]-1)*block+1;i<=b;i++) {
            s[pos[b]].erase(v[i]);
            s[pos[b]].insert(v[i]+=c);
        }
    }
    for(int i=pos[a]+1;i<=pos[b]-1;i++) tag[i]+=c;
}

int query(int a,int b,int c,int ans=-1) {
    for(int i=a;i<=min(pos[a]*block,b);i++)
        if(v[i]+tag[pos[a]]<c) ans=max(ans,v[i]+tag[pos[a]]);
    if(pos[a]!=pos[b])
        for(int i=(pos[b]-1)*block+1;i<=b;i++)
            if(v[i]+tag[pos[b]]<c) ans=max(ans,v[i]+tag[pos[b]]);
    for(int i=pos[a]+1;i<=pos[b]-1;i++) {
        int x=c-tag[i];
        set<int>::iterator it =s[i].lower_bound(x);
        if(it==s[i].begin()) continue; it--;
        ans=max(ans,*it+tag[i]);
    }return ans;
}

int main()
{
    in(n); block=sqrt(n);
    for(int i=1;i<=n;i++) in(v[i]);
    for(int i=1;i<=n;i++) {
        pos[i]=(i-1)/block+1;
        s[pos[i]].insert(v[i]);
    }
    for(int i=1;i<=n;i++) {
        int op,a,b,c;
        in(op),in(a),in(b),in(c);
        if(!op) add(a,b,c);
        else cout<<query(a,b,c)<<endl;
    }
}

分块4:区间加法,区间求和

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
using namespace std;
const int N=5e5+10,inf=2e9;
int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
    return ans*f;
}
int n,m,block;
int pos[N],v[N],tag[N],sum[N];

void add(int a,int b,int c) {
    for(int i=a;i<=min(pos[a]*block,b);i++) v[i]+=c,sum[pos[a]]+=c;
    if(pos[a]!=pos[b])
        for(int i=(pos[b]-1)*block+1;i<=b;i++) v[i]+=c,sum[pos[b]]+=c;
    for(int i=pos[a]+1;i<=pos[b]-1;i++) tag[i]+=c;
}

int query(int a,int b,int ans=0) {
    for(int i=a;i<=min(pos[a]*block,b);i++)
        ans+=v[i]+tag[pos[a]];
    if(pos[a]!=pos[b])
        for(int i=(pos[b]-1)*block+1;i<=b;i++)
            ans+=v[i]+tag[pos[b]];
    for(int i=pos[a]+1;i<=pos[b]-1;i++)
        ans+=sum[i]+block*tag[i];
    return ans;
}

int main()
{
    in(n); block=sqrt(n);
    for(int i=1;i<=n;i++) in(v[i]);
    for(int i=1;i<=n;i++)
        pos[i]=(i-1)/block+1,sum[pos[i]]+=v[i];
    for(int i=1;i<=n;i++) {
        int op,a,b,c;
        in(op),in(a),in(b),in(c);
        if(!op) add(a,b,c);
        else printf("%d\n",query(a,b)%(c+1));
    }
}

分块5:区间开方,区间求和
提示:因为开方一些次数后,数会变成0/1,我们对不全为0/1的块暴力开方,否则跳过

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
using namespace std;
const int N=5e5+10,inf=2e9;
int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
    return ans*f;
}
int n,m,block;
int pos[N],v[N],tag[N],sum[N],vis[N];

void solve(int x) {
    if(vis[x]) return;
    vis[x]=1; sum[x]=0;
    for(int i=(x-1)*block+1;i<=x*block;i++) {
        v[i]=sqrt(v[i]); sum[x]+=v[i];
        if(v[i]>1) vis[x]=0;
    }
}

void update(int a,int b,int c) {
    for(int i=a;i<=min(b,pos[a]*block);i++) {
        sum[pos[a]]-=v[i];
        v[i]=sqrt(v[i]);
        sum[pos[a]]+=v[i];
    }
    if(pos[a]!=pos[b])
        for(int i=(pos[b]-1)*block+1;i<=b;i++) {
            sum[pos[b]]-=v[i];
            v[i]=sqrt(v[i]);
            sum[pos[b]]+=v[i];
        }
    for(int i=pos[a]+1;i<=pos[b]-1;i++) solve(i);
}

int query(int a,int b,int ans=0) {
    for(int i=a;i<=min(pos[a]*block,b);i++)
        ans+=v[i]+tag[pos[a]];
    if(pos[a]!=pos[b])
        for(int i=(pos[b]-1)*block+1;i<=b;i++)
            ans+=v[i]+tag[pos[b]];
    for(int i=pos[a]+1;i<=pos[b]-1;i++)
        ans+=sum[i]+block*tag[i];
    return ans;
}

int main()
{
    in(n); block=sqrt(n);
    for(int i=1;i<=n;i++) in(v[i]);
    for(int i=1;i<=n;i++)
        pos[i]=(i-1)/block+1,sum[pos[i]]+=v[i];
    for(int i=1;i<=n;i++) {
        int op,a,b,c;
        in(op),in(a),in(b),in(c);
        if(!op) update(a,b,c);
        else printf("%d\n",query(a,b)%(c+1));
    }
}

分块6:插入值,单点查询
提示:暴力插入,然后把后面的节点全部后移,当块的大小较大后重构

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
#define pr pair<int,int>
using namespace std;
const int N=5e5+10,inf=2e9;
int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
    return ans*f;
}
int n,m,blo,cnt;
int v[N],st[N];
vector<int>t[N];

pr find(int a) {//找到是哪个块
	int x=1;
	while(a>t[x].size()) 
		a-=t[x].size(),x++;
	return make_pair(x,a-1);//因为vector为0~n-1
}

void rebuild() {
	cnt=0;
	for(int i=1;i<=m;i++) {
		for(vector<int>::iterator it=t[i].begin();it!=t[i].end();it++)
			st[++cnt]=*it;
		t[i].clear();
	}
	blo=sqrt(cnt);
	for(int i=1;i<=cnt;i++)
		t[(i-1)/blo+1].push_back(st[i]);
	m=(cnt-1)/blo+1;
}

void insert(int a,int b) {
	pr q=find(a);
	t[q.first].insert(t[q.first].begin()+q.second,b);
	if(t[q.first].size()>10*blo) rebuild();//重构
}

int main()
{
    in(n); blo=sqrt(n);
    for(int i=1;i<=n;i++) in(v[i]);
	for(int i=1;i<=n;i++)
		t[(i-1)/blo+1].push_back(v[i]);
	m=(n-1)/blo+1;//最终块是哪个,会更新
    for(int i=1;i<=n;i++) {
        int op,a,b,c;
        in(op),in(a),in(b),in(c);
        if(!op) insert(a,b);
        else {
			pr q=find(b);
			printf("%d\n",t[q.first][q.second]);
		}
    }
}

博主蒟蒻,随意转载.但必须附上原文链接

http://www.cnblogs.com/real-l/

posted @ 2018-10-05 19:34  real_l  阅读(443)  评论(0编辑  收藏  举报