2019南京网络赛A 题解

首先O(1)算出 m个点的对应的beauty值,然后就变成了一个二维数点问题,在一个n*n的矩阵上,有m个点,q个询问

每次询问一个矩阵内的值之和。由于n的范围为1e6,二维树状数组加离散化或者二维前缀和加离散化开不下,如果用map存pair

会多加一个log 复杂度为n(logn)(logn) 会T,这里要用到二维偏序预处理加一维树状数组。

在y轴上建立树状数组,对每个点的x轴和y轴进行排序。同时每次询问要求的矩阵[a,b,c,d],就等于

前缀和+[c,d],+[a-1,b-1] , -[a-1,d], -[c,b-1] 。由于我们只要求四个矩阵点(x,y)的前缀和所以对于矩阵点之前的点我们先加进去

然后在矩阵点的时候求出前缀和更新答案,所以排序的时候我们把矩阵点也加入数组中排序。并且让矩阵点在数组中的位置位于实际点之后,同时要记录一下四个矩阵点id 方便更新答案。则对于每个矩阵的ans就为四个矩阵点的前缀和乘以他的系数之和。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int t,n,m,p;
ll c[500005];
struct node
{
    int x,y,val,id;
}pos[500005];

bool cmp(node a, node b)
{
    if(a.x!=b.x)return a.x<b.x;
    if(a.y!=b.y)return a.y<b.y;
    if(a.val!=b.val)return a.val>b.val;
}
int lowbit(int x){return x&(-x);}
void add(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
    return ;
}
ll sum(int x)
{
    ll res=0;
    while(x>0)
    {
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
int get_val(int x, int y, int n)
{
    int w=min(min(x-1,y-1),min(n-x,n-y));
    ll v=2LL*(n-1+n-1-2*(w-1))*w;
    n-=w*2;
    x-=w;
    y-=w;
    if(x==n&&y>1) v+=1LL*(n-y+1);
    else if(y==1&&x>1) v+=1LL*(n-1+n-x+1);
    else if(x==1&&y<n) v+=1LL*(2*(n-1)+y);
    else v+=1LL*(3*(n-1)+x);
    int tot=0;
    while(v)
    {
    	tot+=v%10;
    	v=v/10;
	}
    return tot;
}
ll ans[100005];
int num;
void init()
{
    for(int i=0;i<=n;i++)
    {
        c[i]=0;
    }
    num=0;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&p);
        init();
        for(int i=1;i<=m;i++)
        {
            ++num;
            int a,b;
            scanf("%d%d",&a,&b);
            pos[num].x=a;pos[num].y=b;
            pos[num].id=get_val(a,b,n);
            pos[num].val=1000;
        }
        int a,b,c,d;
        for(int i=1;i<=p;i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            pos[++num].x=c;pos[num].y=d;pos[num].val=1;pos[num].id=i;
            pos[++num].x=a-1;pos[num].y=b-1;pos[num].val=1;pos[num].id=i;
            pos[++num].x=a-1;pos[num].y=d;pos[num].val=-1;pos[num].id=i;
            pos[++num].x=c;pos[num].y=b-1;pos[num].val=-1;pos[num].id=i;
            ans[i]=0;
        }
        sort(pos+1,pos+1+num,cmp);
        //for(int i=1;i<=num;i++)cout<<pos[i].x<<" "<<pos[i].y<<" "<<pos[i].val<<" "<<pos[i].id<<endl;
        for(int i=1;i<=num;i++)
        {
            if(pos[i].val==1000)
            {
                add(pos[i].y,pos[i].id);
            }
            else
            {
                ans[pos[i].id]+=1ll*sum(pos[i].y)*pos[i].val;
                //cout<<ans[pos[i].id]<<endl;
            }
        }
        for(int i=1;i<=p;i++)
        {
            printf("%lld\n",ans[i]);
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值