hdu 4325 Flowers 2012多校1006题 树状数组解法

本文介绍了一种利用树状数组解决区间更新单点查询问题的方法,并通过实例详细解释了如何通过两次添加操作实现区间加法。此外,还讨论了离散化的实现方式及其对效率的影响。

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

这题一看就是区间更新单点查询,比较裸的线段树……当时敲的时候手残了,没敲好,后来队友用树状数组过的……今天我也写了一个树状数组,不过不知道为什么效率不佳,得300+ms才过,可能我离散化写的有问题,写了两个版本的,一个是用stl的,一个没有……离散化我一直都不是太清楚怎么写,自己yy了一个…………

这题用树状数组写的时候其实是树状数组反过来用,sum(x)表示查询x处话的数量,而更新区间则是用两次add

如,我要在区间(2,5)加1,那么我add(2,1)在2的地方加一个1,这时sum(大于等于2)的数都增加了1,那么只要再add(6,-1),这时sum(大于等于6)的数都少了1,等于之前的1白加,而这时,2到5之间那个加的1还是在的,所以这样就满足了(2,5)区间的数加了1

离散化写的很挫…………希望读者能够指点迷津

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX = 100010;
struct point
{
    int x;
    int flag;
    int id;
}p[MAX<<2];
int cmp(const point &a,const point &b)
{
    return a.x<b.x;
}
int lowbit(int p)
{
    return p&(-p);
}
int cnt;
int a[MAX<<2];
void plus(int x,int c)
{
    while(x<=cnt)
    {
        a[x]+=c;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int ans = 0;
    while(x)
    {
        ans+=a[x];
        x-=lowbit(x);
    }
    return ans;
}
int x[3][MAX];
int main()
{
    int cas;
    scanf("%d",&cas);
    for(int t=1; t<=cas; t++)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0; i<n*2; i+=2)
        {
            scanf("%d%d",&p[i].x,&p[i+1].x);
            p[i].flag = 0;
            p[i+1].flag = 1;
            p[i].id = p[i+1].id = i/2;
        }
        for(int i=2*n; i<2*n+m; i++)
        {
            scanf("%d",&p[i].x);
            p[i].flag = 2;
            p[i].id = i - 2 * n;
        }
        sort(p,p+2*n+m,cmp);
        cnt = 0;
        int now = -1;
        for(int i=0; i<2*n+m; i++)
        {
            if(now!=p[i].x)
            {
                cnt++;
                now = p[i].x;
            }
            x[p[i].flag][p[i].id] = cnt;
        }
        memset(a,0,sizeof(a));
        for(int i=0; i<n; i++)
        {
            plus(x[0][i],1);
            plus(x[1][i]+1,-1);
        }
        printf("Case #%d:\n",t);
        for(int i=0; i<m; i++)
        printf("%d\n",sum(x[2][i]));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值