hdu1892 See you(二维树状数组)

本文解析了 HDU 1892 题目的解题思路,采用二维树状数组实现矩阵操作,包括添加、删除、移动书籍及查询子矩阵书籍总数。介绍了树状数组的基本原理及其在频繁更新和查询场景中的高效应用。

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1892

1.题意:

一个矩阵中含有1000*1000个格子,每个格子放了一本书,现在有4种操作:

①'A' 在某个格子添加n本书; ②'D' 在某个格子删除n本书;③'M' 从某个格子移动n本书到另一个格子;

④查询以 x1,y1 x2,y2 为对角线端点的子矩阵中,总共含有多少本书。

2.思路:二维树状数组

树状数组介绍: https://blog.youkuaiyun.com/zzti_xiaowei/article/details/81053094

此题还要注意:

①判断x1,y1 x2,y2 哪个节点靠左。

②注意阅读题目,假如操作的格子不够n本书,则取其所有的书。

③题目是多个case,为了避免每个 case开头都要对数组的初始化,我用set记录了上一次case中修改的那些节点,然后只需要将这些节点更新为1即可。

3.代码:

#include<stdio.h>
#include<set>
using namespace std; 
int n,m;
int lowbit(int x){
    return x & (-x);
}
int arr[1000+5][1000+5];
int cc[1000+5][1000+5];
void update(int x,int y,int add)
{
    for(int i=x;i<=n;i+=lowbit(i)){
        for(int j=y;j<=m;j+=lowbit(j)){
            cc[i][j] += add;
        }
    }
}
int getSum(int x,int y){
    int rs = 0;
    for(int i=x;i>0;i-=lowbit(i)){
        for(int j=y;j>0;j-=lowbit(j)){
            rs += cc[i][j];
        }
    }
    return rs;
}
int max(int a,int b){
    return a>b?a:b;
}
int min(int a,int b){
    return a<b?a:b;
}
struct Node
{
    int x,y;
    Node(int xx,int yy){
        x = xx ; y = yy;
    }    
};
bool operator < (Node a,Node b){
    if(a.x==b.x && a.y==b.y) return false;
    return true;    
}
int main(){
    m=n=1001;
    int cas;
    scanf("%d",&cas);
    int x1,x2,y1,y2;
    int x,y;
    int n1;
    for(int j=1;j<=n;j++){
        for(int k=1;k<=m;k++){
            arr[j][k] = 1;
            update(j,k,1);
        }
    }
    set<Node> s ; 
    for(int i=1;i<=cas;i++){
        set<Node>::iterator it = s.begin();
        while(it!=s.end()){ //只更新上一次case被修改的节点,避免超时TLE
            Node tmp = (*it);
            int now = arr[tmp.x][tmp.y];
            if(now!=1){
                arr[tmp.x][tmp.y] = 1;
                update(tmp.x,tmp.y,1-now);
            }
            it++;
        }
        s.clear();
        printf("Case %d:\n",i);
        int qs;
        scanf("%d",&qs);
        int rs;
        for(int j=1;j<=qs;j++){
            getchar();
            char op;
            scanf("%c",&op);
            switch(op){
                case 'S':
                    scanf("%d",&x1);scanf("%d",&y1);scanf("%d",&x2);scanf("%d",&y2);
                    x1++; y1++; x2++; y2++;
                    if(x1>x2){
                        int tmp = x2;
                        x2 = x1;
                        x1 = tmp;
                    }
                    if(y1>y2){
                        int tmp = y1;
                        y1 = y2;
                        y2 = tmp;
                    }
                    rs = getSum(x2,y2) - getSum(x2,y1-1) - getSum(x1-1,y2) + getSum(x1-1,y1-1);
                    printf("%d\n",rs);
                    break;
                case 'A':
                    scanf("%d",&x);scanf("%d",&y);scanf("%d",&n1);
                    x++;y++;
                    s.insert(Node(x,y)); //记录这个被更新的节点
                    update(x,y,n1);
                    arr[x][y] += n1;
                    break;
                case 'D':
                    scanf("%d",&x);scanf("%d",&y);scanf("%d",&n1);
                    x++;y++;
                    s.insert(Node(x,y));//记录这个被更新的节点
                    n1 = min(n1,arr[x][y]);
                    update(x,y,-n1);
                    arr[x][y] -= n1;
                    break;
                case 'M' : 
                    scanf("%d",&x1);scanf("%d",&y1);scanf("%d",&x2);scanf("%d",&y2);
                    scanf("%d",&n1);
                    x1++;y1++;x2++;y2++;
                    
                    s.insert(Node(x1,y1));//记录这个被更新的节点
                    s.insert(Node(x2,y2));//记录这个被更新的节点
                    
                    n1 = min(n1,arr[x1][y1]);
                    update(x1,y1,-n1);
                    update(x2,y2,n1);
                    arr[x1][y1] -= n1;
                    arr[x2][y2] += n1;
                    break;    
            }
        }
    } 
    return 0;
}//ac c++ 405MS

总结:树状数组 就是利用二进制的特性 去统计前n项和。不论是修改还是查询操作都是O(logN) 的操作,此处N是数组长度。

适用于 数组类型 频繁更新和查询的情况,是非常优秀的一种创新的"数据结构",但我还是无法证明它的正确性,再次膜拜大佬。

【从高压输电线的架空地线中汲取电能】一个25千瓦受控电源从735千伏线路的架空地线中汲取电能的SimPowerSystems模型(Simulink仿真实现)内容概要:本文介绍了一个基于SimPowerSystems的Simulink仿真模型,用于模拟从735千伏高压输电线的架空地线中汲取25千瓦电能的受控电源系统。该模型聚焦于高压输电线路中架空地线的能量回收技术,通过仿真手段实现对电能采集过程的建模与控制策略验证,体现了电力系统中新型能源获取方式的技术可行性与工程应用潜力。文中还提及该资源属于一系列电力系统仿真研究的一部分,涵盖微电网、储能优化、碳流追踪、鲁棒调度等多个前沿方向,配套提供Matlab/Simulink代码及网盘资料链接,便于科研人员复现与拓展研究。; 适合人群:具备电力系统基础知识、熟悉Matlab/Simulink仿真环境,从事电力工程、能源回收或智能电网相关研究的科研人员及研究生;有一定编程与建模仿真经验的高年级本科生或工程技术人员。; 使用场景及目标:①研究高压输电线路中架空地线的能量回收机制与建模方法;②掌握基于Simulink的电力系统仿真技术,特别是受控电源与电网交互的动态特性分析;③为开展能源 harvesting、分布式供能、电力电子变换器控制等相关课题提供参考模型与技术支撑; 阅读建议:建议结合提供的仿真模型文件进行实操演练,重点理解系统结构设计、参数设置与控制逻辑实现;同时可延伸学习文档中提到的其他电力系统优化与仿真案例,以拓宽研究视野和技术积累。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值