BestCoder 2nd Anniversary Jewelry 离散化加扫描线

本文介绍了一种通过抽象矩形面积来解决特定子区间计数问题的方法。对于给定序列和时间值time,算法计算序列中数量恰好为time的子区间个数,利用矩形面积的概念简化计算过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题在于怎么抽象出矩形面积。。。
求某个数数量恰好是time的子区间个数
当两个点c和d都是a1且两点之间的a1数量等于time时那左端点可以是c之前的且不是a1的那个点的任意一点,右端点可以是d之后的且不是a1的任何一点,那左端点可以移动的左右范围当做矩形长的左右端点的x值,右端点可以移动的左右范围当做矩形长的上下端点的y值这就是个矩形了。。。然后求总面积

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
#include<cstring>
#define maxn 100005
#define lson i<<1
#define rson (i<<1)+1
#define LL long long
using namespace std;
int a[maxn],b[maxn],time,n,l;
int len[maxn*4],cnt[maxn*4];
vector<int>ve[maxn];
struct line{
    int x1,x2,y,flag;
    line(){};
    line(int a,int b,int c,int d):x1(a),x2(b),y(c),flag(d){};
}lin[maxn*4];

void pushUp(int i,int l,int r)
{
     if(cnt[i])len[i] = r-l+1;
     else {
        if(l==r)len[i] = 0;
        else len[i] = len[lson]+len[rson];
     }
}

void update(int i,int l,int r,int L,int R,int flag)
{
     if(l==L&&r==R)
     {
        cnt[i]+=flag;
        pushUp(i,l,r);
        return ;
     }
     int mid = (l+r)/2;
     if(L>mid) update(rson,mid+1,r,L,R,flag);
     else if(R<=mid)  update(lson,l,mid,L,R,flag);
     else {
        update(rson,mid+1,r,mid+1,R,flag);
        update(lson,l,mid,L,mid,flag);
     }
     pushUp(i,l,r);
}

bool cmp(line l1,line l2)
{
     return l1.y<l2.y;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&time);
        l = 0;
        for(int i=0;i<n;i++)scanf("%d",&a[i]),b[i] = a[i];
        memset(len,0,sizeof(len));
        memset(cnt,0,sizeof(cnt));
        sort(b,b+n);
        int am = unique(b,b+n)-b;
        for(int i=0;i<am;i++)
            ve[i].clear();
        for(int i=0;i<n;i++)
        {
            int pre = lower_bound(b,b+am,a[i])-b;
            ve[pre].push_back(i);
        }
        for(int i=0;i<am;i++)
            for(int j=0;j+time-1<ve[i].size();j++)
            {
                lin[l++] = line(j?ve[i][j-1]+1:0,ve[i][j],ve[i][j+time-1],1);
                lin[l++] = line(j?ve[i][j-1]+1:0,ve[i][j],(j+time<ve[i].size()?ve[i][j+time]-1:n-1)+1,-1);
            }
        sort(lin,lin+l,cmp);
        LL ans = 0;
        for(int i=0;i<l-1;i++)
        {
            update(1,0,n-1,lin[i].x1,lin[i].x2,lin[i].flag);
            ans = ans + ((LL)lin[i+1].y-lin[i].y)*len[1];
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值