CF853C Boredom

一、题目

点此看题

题目说的很不清楚,我再来解释一下:

有一个 n × n n\times n n×n 的矩阵,一开始有人在上面标记了 n n n个点(不重行,不重列),询问给定一个矩形,问有多少选两个点组成的矩形与给定的矩形相交(挨着也行)。

二、解法

正难则反,有一种计算方法就是用所有矩形减去不相交的矩形, x x x个点能生成的矩形数为 x ( x − 1 ) 2 \frac{x(x-1)}{2} 2x(x1)

可以先减去上下左右四个方向所能生成的矩形数量,那这样会不会算重呢?答案就是我们减多了,因为左下角,右下角,左上角,右上角所能生成的矩形数量都被算了两遍,所以要加回去。

本题范围很大,但是点很不多,可以用主席树来维护前缀和,时间复杂度&空间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include <cstdio>
#define LL long long
const int N = 200005;
const int M = 30*N;
int read()
{
    int x=0,flag=1;char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,q,cnt,rt[N],sum[M],ls[M],rs[M];
int ins(int x,int l,int r,int id)
{
    int t=++cnt;
    sum[t]=sum[x]+1;ls[t]=ls[x];rs[t]=rs[x];
    if(l==r) return t;
    int mid=(l+r)>>1;
    if(mid>=id)
        ls[t]=ins(ls[x],l,mid,id);
    else
        rs[t]=ins(rs[x],mid+1,r,id);
    return t;
}
int ask(int x,int y,int l,int r,int L,int R)
{
    if(l>R || L>r) return 0;
    if(L<=l && r<=R) return sum[y]-sum[x];
    int mid=(l+r)>>1;
    return ask(ls[x],ls[y],l,mid,L,R)+ask(rs[x],rs[y],mid+1,r,L,R);
}
LL cal(int x)
{
    return 1ll*x*(x-1)/2;
}
int main()
{
    n=read(),q=read();
    for(int i=1;i<=n;i++)
    {
        int x=read();
        rt[i]=ins(rt[i-1],1,n,x);
    }
    while(q--)
    {
        int a=read(),b=read(),c=read(),d=read();
        LL res=cal(n)-cal(a-1)-cal(b-1)-cal(n-c)-cal(n-d);
        if(b>1)
        {
            res+=cal(ask(rt[0],rt[a-1],1,n,1,b-1));
            res+=cal(ask(rt[c],rt[n],1,n,1,b-1));
        }
        if(d<n)
        {
            res+=cal(ask(rt[0],rt[a-1],1,n,d+1,n));
            res+=cal(ask(rt[c],rt[n],1,n,d+1,n));
        }
        printf("%lld\n",res);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值