码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-10-05 20:25:24      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:二分   inf   space   lse   加法   跳过   ++   clear   www   

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)<<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));
    }
}

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

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

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

标签:二分   inf   space   lse   加法   跳过   ++   clear   www   

原文地址:https://www.cnblogs.com/real-l/p/9745628.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!