前缀和&&差分(模板)(一维+二维) +hdu 6514(+动态指针)

前缀和&&差分(模板)(一维+二维)   +hdu 6514(+动态指针) 

一维前缀和:

void init(int n){
    sum[0]=0;
    for(int i=1;i<=n;i++)sum[i]=a[i]+sum[i-1];
}
LL get(int l,int r) {return sum[r]-sum[l-1];}

 

 一维差分:

update(int l,int r,int x){dis[l]=dis[l]+x;dis[r+1]=dis[r+1]-x;}//左端打上标记+x,右端+1处打上标记-x
updateall(int n){
    for(int i=1;i<=n;i++){//前缀和思想去掉标记,此时val[i]里记录的是增加量
        val[i]=dis[i]+val[i-1];
    }
}

 

CF C. Covered Points Count

题意:给你n个区间,每个区间的每个a[i]++,求a[i]==k有几个(-1<=k<=n)。

把所有的点打上标记后sort,然后依次处理.....有点讨厌这种处理....

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int max_n = 2e5+5;
LL ans[max_n];
struct no{LL p,val;};
vector<no>v;
bool operator<(const no &x,const no &y){return x.p<y.p;}
int main(){
    int n;scanf("%d",&n);for(int i=1;i<=n;i++){
        LL x,y;scanf("%lld%lld",&x,&y);
        v.push_back(no{x,1});v.push_back(no{y+1,-1});
    }sort(v.begin(),v.end());
    LL add=v[0].val,now=v[0].p;
    for(int i=1;i<v.size();){
        for(int j=i;j<v.size();j++){
            if(v[j].p==now){add=add+v[j].val;i++;}
            else {
                ans[add]+=v[j].p-now;
                add+=v[j].val;
                now=v[j].p;
                i=j+1;
                break;
            }
        }
    }
    for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
    return 0;
}

然后一维 TO 二维 !!

 求前缀和时,求sum(i,j)即整个大矩形的值,那么就是 黑色+蓝色+绿色-紫色。

求子矩形时,求紫色的矩形的值,那么就是   整个大矩形的值-蓝色-绿色+黄色。

二维前缀和:

void init(int n,int m){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
        }
    }
}
LL get(int x1,int y1,int x2,int y2){
    return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}

一样前缀和思想,这里在要增加的区域,左上右下打上+x标记,左下右上打上-x标记,照上面的转移即可。

二维差分:

void update(int x1,int y1,int x2,int y2,int x){
    sum[x1][y1]+=x;sum[x2+1][y2+1]+=x;
    sum[x1][y2+1]-=x;sum[x2+1][y1]-=x;
}
void updateall(int n,int m){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            sum[i][j]+=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];
        }
    }
}

hdu 6514

 

题意给你p个子矩形,再给出q个询问,问是否询问给出的矩形能被给出的矩形(可多个)覆盖。

那就是板子题了,将所有已经被覆盖的标记为1,判断询问的矩形面积==询问矩形的值即可。

这里需要动态数组。(我也不知道为什么vector会MLE鸭)

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int max_n = 1e7+5;
int **sum;
void update(int x1,int y1,int x2,int y2,int x){
    sum[x1][y1]+=x;sum[x2+1][y2+1]+=x;
    sum[x1][y2+1]-=x;sum[x2+1][y1]-=x;
}
void updateall(int n,int m){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            sum[i][j]+=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];
        }
    }
}
void init(int n,int m){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            sum[i][j]=sum[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
        }
    }
}
LL get(int x1,int y1,int x2,int y2){
    return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        sum=new int*[n+5];
        for(int i=0;i<n+5;i++)
            sum[i]=new int[m+5];
        for(int i=0;i<=n+1;i++){
            for(int j=0;j<=m+1;j++){
                sum[i][j]=0;
            }
        }
        int p;scanf("%d",&p);while(p--){//标记
            int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            update(x1,y1,x2,y2,1);
        }
        updateall(n,m);//消除标记
        for(int i=0;i<=n;i++){
            for(int j=0;j<=m;j++) if(sum[i][j]) sum[i][j]=1;
        }
        init(n,m);//求前缀和
        int q;scanf("%d",&q);while(q--){
            int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            int sss=get(x1,y1,x2,y2);
            if(sss==(x2-x1+1)*(y2-y1+1)) puts("YES");
            else puts("NO");
        }
        delete sum;
    }

    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值