分块的一些题(入门)

POJ-3468  区间加和区间和查询  之前作为线段树入门写过 这次用分块写一下 

区间主要就是两种情况 在同一个块or不同块。整块的区域我们只要成段更新就好了,反之暴力更新~

 1 #include<cmath>
 2 #include<queue>
 3 #include<stack>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<iostream>
 7 #include<algorithm>
 8 #define FIN freopen("input.txt","r",stdin)
 9 #define ll long long
10 #define mod 1000000007
11 #define lson l,m,rt<<1
12 #define rson m+1,r,rt<<1|1
13 const int maxn = 105000+5;
14 using namespace std;
15 int q[maxn];
16 int belong[maxn],l[maxn],r[maxn];
17 ll sum[maxn],add[maxn];
18 int n;
19 void build(){
20     int block=sqrt(n);
21     if(block==0) block=1;
22     int tot=n/block;
23     if(n%block!=0)tot++;
24     for(int i=1;i<=n;i++){
25         belong[i]=(i-1)/block+1;
26     }
27     for(int i=1;i<=tot;i++){
28         l[i]=(i-1)*block+1;
29         r[i]=i*block;
30         for(int j=l[i];j<=(i==tot?n:r[i]);j++)
31             sum[i]+=q[j];
32     }
33     r[tot]=n;
34 }
35 void update(int x,int y,int c){
36     if(belong[x]==belong[y]){
37         for(int i=x;i<=y;i++){
38             q[i]+=c;sum[belong[x]]+=c;
39         }
40     }else {
41         for(int i=x;i<=r[belong[x]];i++){
42             q[i]+=c;sum[belong[x]]+=c;
43         }
44         for(int i=l[belong[y]];i<=y;i++){
45             q[i]+=c;sum[belong[y]]+=c;
46         }
47         for(int i=belong[x]+1;i<belong[y];i++)
48             add[i]+=c;
49     }
50 }
51 ll query(int x,int y){
52     ll ans=0;
53     if(belong[x]==belong[y]){
54         for(int i=x;i<=y;i++)
55             ans+=q[i]+add[belong[x]];
56         return ans;
57     }else {
58         for(int i=x;i<=r[belong[x]];i++)
59             ans+=q[i]+add[belong[x]];
60         for(int i=l[belong[y]];i<=y;i++)
61             ans+=q[i]+add[belong[y]];
62         for(int i=belong[x]+1;i<belong[y];i++)
63             ans+=add[i]*(r[i]-l[i]+1)+sum[i];
64         return ans;
65     }
66 
67 }
68 int main()
69 {
70      #ifndef ONLINE_JUDGE
71         FIN;
72        #endif
73     int m;
74     scanf("%d %d",&n,&m);
75     for(int i=1;i<=n;i++){
76         scanf("%d",&q[i]);
77     }
78     build();
79     while(m--){
80         char op[3];
81         int l,r,c;
82         scanf("%s",op);
83         if(op[0]=='Q'){
84             scanf("%d %d",&l,&r);
85             printf("%I64d\n",query(l,r));
86         }else {
87             scanf("%d %d %d",&l,&r,&c);
88             update(l,r,c); 
89         }
90     }
91     return 0;
92 }
View Code

 

POJ-2104 区间第k大 之前主席树入门写过

思路:我们分块后,块内排序,然后每次我们二分数组的下标。每次对于二分的值,check下L到R区间里值是第几大,最后更新下最大值就好了。

#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FIN freopen("input.txt","r",stdin)
#define ll long long
#define mod 1000000007
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 100000+5;
using namespace std;
int q1[maxn],q2[maxn],q3[maxn];
int belong[maxn],l[maxn],r[maxn];
int n;
void build(){
    int block=sqrt(n);    
    if(block==0) block=1;
    int tot=n/block;
    if(n%block) tot++;
    for(int i=1;i<=n;i++){
        belong[i]=(i-1)/block+1;
    }
    for(int i=1;i<=tot;i++){
        l[i]=(i-1)*block+1;
        r[i]=i*block;
        if(i==tot) r[i]=n;
        sort(q1+l[i],q1+r[i]+1);
    }
}
int check(int L,int R,int val){
    int ans=0;
    if(belong[L]==belong[R]){
        for(int i=L;i<=R;i++)
            if(q2[i]<val) ans++;
            return ans; 
    }else{
        for(int i=L;i<=r[belong[L]];i++)
            if(q2[i]<val) ans++;
        for(int i=l[belong[R]];i<=R;i++)
            if(q2[i]<val) ans++;
        for(int i=belong[L]+1;i<belong[R];i++){
            int left=l[i];
            int right=r[i];
            int res=0;
            while(left<=right){
                int m=(left+right)>>1;
                if(q1[m]<val){
                    left=m+1;
                    res=max(res,m-l[i]+1);
                }
                else right=m-1;
            }
            ans+=res;
        }
        return ans;
    }
    
}
int find(int L,int R,int K){
    int l=1;
    int r=n;
    int ans=-(1e9+7);
    while(l<=r){
        int m=(l+r)>>1;
        if(check(L,R,q3[m])<K){
            ans=max(ans,q3[m]);
            l=m+1;
        }
        else r=m-1;
    }
    return ans;

}
int main()
{
     #ifndef ONLINE_JUDGE
        FIN;
       #endif
    int m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&q1[i]);
        q2[i]=q3[i]=q1[i];
    }
    build();
    sort(q3+1,q3+1+n);
    for(int i=1;i<=m;i++){
          int L,R,k;
          scanf("%d %d %d",&L,&R,&k);
          printf("%d\n",find(L,R,k));
    }
    return 0;
}
View Code

 

BZOJ-2957 

思路:线段不想交,意味着后面的组成的线段斜率要比前面大即可,每次操作我们更新当前的块,然后每次我们只要求出大于等于前一块的最高值的数量,累加即可。

#include<bits/stdc++.h>
#define FIN freopen("input.txt","r",stdin)
#define ll long long
#define mod 1000000007
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 100000+5;
using namespace std;
int belong[maxn],tot;
struct node{
    int l,r;
    vector<double> v;
}p[maxn];
double H[maxn];
int n,m;
void build(){
    int k=sqrt(n);
    tot=n/k;
    if(n%k) tot++;
    for(int i=1;i<=n;i++){
     belong[i]=(i-1)/k+1;
    }
    for(int i=1;i<=tot;i++){
        p[i].l=(i-1)*k+1;
        p[i].r=i*k;
    }
    p[tot].r=n;
}
int solve(int x,int h){
    int to=belong[x];
    H[x]=1.0*h/x;
    double mx=0.0;
    p[to].v.clear();
    for(int i=p[to].l;i<=p[to].r;i++){
        if(H[i]>mx){
            mx=H[i];
            p[to].v.push_back(H[i]);
        }
    }
    mx=0.0;
    int ans=0;
    for(int i=1;i<=tot;i++){
        if(p[i].v.size()==0) continue;
    ans+=p[i].v.end()-upper_bound(p[i].v.begin(),p[i].v.end(),mx);
    mx=max(mx,*p[i].v.rbegin());
    }
    return ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
        FIN;
    #endif
    scanf("%d %d",&n,&m);
    build();
    for(int i=1;i<=m;i++){
        int x,h;
        scanf("%d %d",&x,&h);
        printf("%d\n",solve(x,h));
    }
}
View Code

 

posted @ 2019-02-16 10:56  MengX  阅读(328)  评论(0编辑  收藏  举报

梦想不是空想