zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",t[q.first][q.second]);
    		}
        }
    }
    

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

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

  • 相关阅读:
    C++STL——vector
    大数常用计算模板及例题
    在线算法&离线算法
    线段树——hdu1166敌兵布阵
    C++STL——堆栈
    C++STL——优先队列
    C++STL——队列
    图的建立——图的两种存储结构
    Manacher算法——最长回文子串
    HttpClient的几个实现类
  • 原文地址:https://www.cnblogs.com/real-l/p/9745628.html
Copyright © 2011-2022 走看看