Gym 101991D Dull Chocolates 二维偏序 离散化

cf老进不去就不发链接了,直接讲题意好了。

 

        在n*m的区域内给你k个点,现在要你统计出,以(1,1)为左下角,有多少个子矩阵内包含奇数个点。

 

做法:

      类似二维偏序的思想,因为给你的点最多只有1000个点,所以一开始要先用离散化把这些点变得集中一点,然后用类似二维偏序的方向,for每一个点同时用树状数组维护y方向上有多少个点,每次计算包含这个点并以其作为最右上角之后有多少个矩阵,这里要分四类讨论,即,这个点在x方向上为最上方,在y方向上为最右端,在最左上角的时候与(n,m)进行比较,否则要找其下一个点(即要么比它x大,要么比它y大),计算其不包含下一个点之间有多少个矩阵。

      具体可以看代码里的实现。

 


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1005;
int sum[maxn],tmpx[maxn],tmpy[maxn];
int x[maxn],y[maxn],mp[maxn][maxn];
int lowbit(int x){
    return x&(-x);
}
void add(int pos){
    while(pos<=maxn){
        sum[pos]++;
        pos+=lowbit(pos);
    }
}
int query(int pos){
    int ans=0;
    while(pos){
        ans+=sum[pos];
        pos-=lowbit(pos);
    }
    return ans;
}
int main(){
    freopen("dull.in","r",stdin);
    int t,n,m,k,numx,numy,aimx,aimy;
    cin>>t;
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        memset(mp,0,sizeof(mp));
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=k;i++){
            scanf("%d%d",&x[i],&y[i]);
            tmpx[i]=x[i],tmpy[i]=y[i];
        }
        sort(tmpx+1,tmpx+1+k); sort(tmpy+1,tmpy+1+k);
        numx=unique(tmpx+1,tmpx+1+k)-tmpx-1;
        numy=unique(tmpy+1,tmpy+1+k)-tmpy-1;
        for(int i=1;i<=k;i++){
            x[i]=lower_bound(tmpx+1,tmpx+1+numx,x[i])-tmpx;
            y[i]=lower_bound(tmpy+1,tmpy+1+numy,y[i])-tmpy;
            mp[x[i]][y[i]]++;
        }
        ll ans=0;
        sort(x+1,x+1+k);sort(y+1,y+1+k);
        aimx=unique(x+1,x+1+k)-x-1,aimy=unique(y+1,y+1+k)-y-1;
        for(int i=1;i<=aimx;i++){
            for(int j=1;j<=aimy;j++){
                if(mp[x[i]][y[j]])
                    add(y[j]);
                int nowsum=query(y[j]);
                if(nowsum%2){
                    if(i==aimx&&j==aimy){
                        ans+=(ll)(n-tmpx[x[i]]+1)*(ll)(m-tmpy[y[j]]+1);
                    }
                    else if(i==aimx){
                        ans+=(ll)(n-tmpx[x[i]]+1)*(ll)(tmpy[y[j+1]]-tmpy[y[j]]);
                    }
                    else if(j==aimy){
                        ans+=(ll)(m-tmpy[y[j]]+1)*(ll)(tmpx[x[i+1]]-tmpx[x[i]]);
                    }
                    else {
                        ans+=(ll)(tmpx[x[i+1]]-tmpx[x[i]])*(ll)(tmpy[y[j+1]]-tmpy[y[j]]);
                    }
                }
            }
        }
        printf("%lld %lld\n",ans,(ll)n*m-ans);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值