HDU 4456 Crowd

本文介绍了解决一道竞赛题目的两种方法:一种是利用二维树状数组结合哈希表进行高效的区间更新与查询;另一种是采用一维树状数组配合平衡树实现相同功能。文章提供了详细的代码实现。

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

去年区域赛留下来的遗憾题之一。

此题要考的是坐标转换后的二维树状数组,难点在于内存开不下,需要20000*20000,现场赛胆大的直接开了这么大就过了,向我们这种胆小的就直接被吓傻了。

hdu上内存32768K。

由树状数组的性质可知每次最多只会更新log(n)次,因此二维树状数组总共会更新m * log(n)*log(n)个地方,所以想办法存这些值就可以了,map会超时,搞个靠谱点的hash就可以了。

另一种解法估计就是出题人想考的,第一维照样用树状数组,第二维再套个平衡树来维护在这个范围内的区间和。

第二种解法代码:

#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <bitset>
#include <string.h>
#include <map>
#include <set>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define sqr(x) ((x)*(x))
using namespace std;
const double eps=1e-8;

int n,m;
const int N = 2000000;

int key[N],sz[N],lc[N],rc[N],w[N],sum[N];
int num;


void newnode(int i)
{
    key[i] = sz[i] = lc[i] = rc[i] = w[i] = sum[i] = 0;
}
class sbtree
{
public:
    int root;
    void clear()
    {
        newnode(++num);
        root = num;
        sz[root] = 1;
    }
    void Insert(int &root,int val,int ww)
    {
        if (root == 0)
        {
            root = ++num;
            lc[root] = rc[root] = 0;
            sz[root] = 1;
            key[root] = val;
            w[root] = ww;
            sum[root] = ww;
            return ;
        }
        sum[root] += ww;
        sz[root] ++;
        if (val < key[root])
        {
            Insert(lc[root] , val , ww);
        }
        else
        {
            Insert(rc[root] , val , ww);
        }
        maintain(root , !(val < key[root]));
    }

    int query(int val){
        int tmp = root;
        int ans = 0;
        while(tmp){
            if(key[tmp] <= val){
                ans += sum[lc[tmp]] + w[tmp];
                tmp = rc[tmp];
            }
            else{
                tmp = lc[tmp];
            }
        }
        return ans;
    }

    void LeftRotate(int &root)
    {
        int temp = rc[root];
        rc[root] = lc[temp];
        lc[temp] = root;
        sz[temp] = sz[root];
        sum[temp] = sum[root];
        sz[root] = 1 + sz[lc[root]] + sz[rc[root]];
        sum[root] = sum[lc[root]] + sum[rc[root]] + w[root];
        root = temp;
    }
    void RightRotate(int &root)
    {
        int temp = lc[root];
        lc[root] = rc[temp];
        rc[temp] = root;
        sz[temp] = sz[root];
        sum[temp] = sum[root];
        sz[root] = 1 + sz[lc[root]] + sz[rc[root]];
        sum[root] = sum[lc[root]] + sum[rc[root]] + w[root];
        root = temp;
    }
    void maintain(int &root , bool flag)
    {
        if (root == 0) return ;
        if ( !flag )   // 调整左子树
        {
            if ( sz[lc[lc[root]]] > sz[rc[root]] )
            {
                RightRotate( root );
            }
            else if ( sz[rc[lc[root]]] > sz[rc[root]] )
            {
                LeftRotate( lc[root] );
                RightRotate( root );
            }
            else
            {
                return ;
            }
        }
        else     // 调整右子树
        {
            if ( sz[rc[rc[root]]] > sz[lc[root]] )
            {
                LeftRotate( root );
            }
            else if ( sz[lc[rc[root]]] > sz[lc[root]] )
            {
                RightRotate( rc[root] );
                LeftRotate( root );
            }
            else
            {
                return ;
            }
        }
        maintain(lc[root] , false);
        maintain(rc[root] , true);
        maintain(root , false);
        maintain(root , true);
    }

} sbt[30000];



int lb(int x)
{
    return x&(-x);
}
void ch(int &x,int &y)
{
    int nx = n+x-y;
    int ny = x+y-1;
    x = nx;
    y = ny;
}
void initval()
{
    num = 0;
    for(int i=1; i<=2*n; i++)
        sbt[i].clear();
}


void add(int x,int y,int z)
{
    for(int i=x; i<=2*n; i+=lb(i))
        sbt[i].Insert(sbt[i].root,y,z);
    }
int get(int x,int y1,int y2)
{
    int ans = 0;
    for(int i=x; i>0; i-=lb(i))
        ans += sbt[i].query(y2) - sbt[i].query(y1);
    return ans;
}
int main()
{
//    freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
    while(1)
    {
        scanf("%d",&n);
        if(n==0) return 0;
        scanf("%d",&m);
        initval();
        while(m--)
        {
            int type,x,y,z;
            scanf("%d%d%d%d",&type,&x,&y,&z);
            if(type==1)
            {
                ch(x,y);
                add(x,y,z);
            }
            else
            {
                int a,b,c,d;
                a = x - z;
                b = y;
                c = x + z;
                d = y;
                ch(a,b);
                ch(c,d);

                a = max(1,a);
                c = min(2*n,c);

                a--;
                b--;
                printf("%d\n",get(c,b,d) - get(a,b,d) );
            }
        }
    }
    return 0;
}

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 “STC单片机电压测量”是一个以STC系列单片机为基础的电压检测应用案例,它涵盖了硬件电路设计、软件编程以及数据处理等核心知识点。STC单片机凭借其低功耗、高性价比和丰富的I/O接口,在电子工程领域得到了广泛应用。 STC是Specialized Technology Corporation的缩写,该公司的单片机基于8051内核,具备内部振荡器、高速运算能力、ISP(在系统编程)和IAP(在应用编程)功能,非常适合用于各种嵌入式控制系统。 在源代码方面,“浅雪”风格的代码通常简洁易懂,非常适合初学者学习。其中,“main.c”文件是程序的入口,包含了电压测量的核心逻辑;“STARTUP.A51”是启动代码,负责初始化单片机的硬件环境;“电压测量_uvopt.bak”和“电压测量_uvproj.bak”可能是Keil编译器的配置文件备份,用于设置编译选项和项目配置。 对于3S锂电池电压测量,3S锂电池由三节锂离子电池串联而成,标称电压为11.1V。测量时需要考虑电池的串联特性,通过分压电路将高电压转换为单片机可接受的范围,并实时监控,防止过充或过放,以确保电池的安全和寿命。 在电压测量电路设计中,“电压测量.lnp”文件可能包含电路布局信息,而“.hex”文件是编译后的机器码,用于烧录到单片机中。电路中通常会使用ADC(模拟数字转换器)将模拟电压信号转换为数字信号供单片机处理。 在软件编程方面,“StringData.h”文件可能包含程序中使用的字符串常量和数据结构定义。处理电压数据时,可能涉及浮点数运算,需要了解STC单片机对浮点数的支持情况,以及如何高效地存储和显示电压值。 用户界面方面,“电压测量.uvgui.kidd”可能是用户界面的配置文件,用于显示测量结果。在嵌入式系统中,用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值