HDU-2642-Stars

题意:

输入一个M,然后M次操作。'B'表示增加一个点,坐标为(x, y),如果存在不操作。'D'表示删除一个点,坐标为(x, y),如果不存在不操作。'Q'表示一次询问,输出给定范围内点的个数。

思路1:

如果本题将二维转换成一维。可以用前缀和的思想,假如求线段[y1, y2]上面点的数量可以用[0, y2]上面点的数量减去[0, y1 - 1]上面点的数量,这是基础的树状数组。那么由于输入的坐标都是整数,且x和y的范围都在1000以内,我们可以开1000个树状数组进行遍历。将二维转换成1000个一维;

  • 解法1(数据水才过的,非正规解法)
    Accepted2642312MS6308K1775 BG++
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 1005;
    // 开MAXN个树状数组, tree[i]对应x轴为i的情况 
    int tree[MAXN][MAXN];
    // 记录各个点是否存在 
    bool bright[MAXN][MAXN];
    int lowbit(int n) {
        return n & (-n);
    }
    void add(int x, int y, int v) {
        while (y < MAXN) {
            tree[x][y] += v;
            y += lowbit(y);
        }
    }
    int query(int id, int n) {
        int res = 0;
        while (n != 0) {
            res += tree[id][n];
            n -= lowbit(n);
        }
        return res;
    }
    int main() {
        int n, x1, y1, x2, y2;
        char op;
        scanf("%d%*c", &n);
        while (n--) {
            scanf("%c", &op);
            if (op == 'Q') {
                int sum = 0;
                scanf("%d%d%d%d%*c", &x1, &x2, &y1, &y2);
                // 树状数组的0号坐标无意义,为避免使用0号坐标把所有坐标都加1,下面的x1++, y1++;也是出于同样原因 
                x1++, x2++, y1++, y2++;
                // 题中没有说明x1, x2的大小和y1, y2的大小,所以要判断一下。在此栽过 
                if (x1 > x2) {
                    swap(x1, x2);
                }
                if (y1 > y2) {
                    swap(y1, y2);
                }
                for (int i = x1; i <= x2; i++) {
                    sum += query(i, y2) - query(i, y1 - 1);
                }
                printf("%d\n", sum);
            } else {
                scanf("%d%d%*c", &x1, &y1);
                x1++, y1++;
                if (op == 'B') {
                    if (bright[x1][y1]) {
                        continue;
                    }
                    add(x1, y1, 1);
                    bright[x1][y1] = true;
                } else {
                    if (!bright[x1][y1]) {
                        continue;
                    }
                    add(x1, y1, -1);
                    bright[x1][y1] = false;
                }
            }
        }
        return 0;
    } 

    看上去不错,能AC,312MS。但这完全是因为数据水。让我们算一下复杂度:对于每次查询,遍历x1到x2,最多1000次,树状数组查询是log的,再乘log1000(大约是10),操作次数的上限是100000。乘一下就是1e9。这个运算量不是2秒能跑出来的。

思路2:

假设遇到一个查询操作:x1 = 1, x2 = 4, y1 = 1, y2 = 7;

y1 - 1等于0,所以按上面的思路我们可以忽略掉query(i, y1 - 1);变成for(int i = 1; i <= 4; i++) sum += query(i, 7);

调试或者用知道树状数组原理可以推出

当i == 1时, query(i, 7) == tree[1][7] + tree[1][6] + tree[1][4];

当i == 2时, query(i, 7) == tree[2][7] + tree[2][6] + tree[2][4];

当i == 3时, query(i, 7) == tree[3][7] + tree[3][6] + tree[3][4];

当i == 4时, query(i, 7) == tree[4][7] + tree[4][6] + tree[4][4];

会发现每次都是tree[i][7] + tree[i][6] + tree[i][4];

拆成三块就是 for (int i = 1; i <= 4; i++) sum += tree[i][7]; for (int i = 1; i <= 4; i++) sum += tree[i][6]; for (int i = 1; i <= 4; i++) sum += tree[i][4];

这里又用到了前缀和,如果有一颗关于tree[][7]的树状数组久可以用log的级别求出for (int i = 1; i <= 4; i++) sum += tree[i][7];

这个例子省略y1方便理解,加上y1也就是用同样的方式把 y2 改成 y1 求解一次,然后相减

语言表达能力有限,如果看不懂,那就结合代码再看吧

  • 解法2
    Accepted2642109MS6304K1940 BG++
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 1005;
    int tree[MAXN][MAXN];
    bool bright[MAXN][MAXN];
    int lowbit(int n) {
        return n & (-n);
    }
    void add2(int y, int x, int v) { 
        while (x < MAXN) {
            tree[y][x] += v;
            // 因为是树状数组的形式,所以只用把相关的位加v就行了 
            x += lowbit(x);
        }
    }
    void add1(int x, int y, int v) {
        while (y < MAXN) {
            // 本来是tree[x][y] += v;现在要以树状数组的形式把tree[x][y]到tree[MAXN - 1][y]都加 v; 
            add2(y, x, v);
            y += lowbit(y);
        }
    }
    // query2相当于第一份代码里的for(int i = x1; i <= x2; i++)效率快很多 
    int query2(int y, int x) {
        int res = 0;
        while (x != 0) {
            res += tree[y][x];
            x -= lowbit(x);
        }
        return res;
    }
    int query1(int y, int x1, int x2) {
        int res = 0;
        while (y != 0) {
            res += query2(y, x2) - query2(y, x1 - 1);
            y -= lowbit(y);
        }
        return res;
    }
    int main() {
        int n, x1, x2, y1, y2;
        char op;
        scanf("%d%*c", &n);
        while (n--) {
            scanf("%c", &op);
            if (op == 'Q') {
                scanf("%d%d%d%d%*c", &x1, &x2, &y1, &y2);
                x1++, x2++, y1++, y2++; 
                if (x1 > x2) {
                    swap(x1, x2);
                }
                if (y1 > y2) {
                    swap(y1, y2);
                } 
                printf("%d\n", query1(y2, x1, x2) - query1(y1 - 1, x1, x2));
            } else {
                scanf("%d%d%*c", &x1, &y1);
                x1++, y1++;
                if (op == 'B') {
                    if (bright[x1][y1]) {
                        continue;
                    }
                    add1(x1, y1, 1);
                    bright[x1][y1] = true;
                } else {
                    if (!bright[x1][y1]) {
                        continue;
                    }
                    add1(x1, y1, -1);
                    bright[x1][y1] = false;
                }
            }
        }
        return 0;
    } 

    之前的树状数组都是不带变化直接照模板的,终于碰上了一道要变形的。纪念一下第一道树状数组变形题

转载于:https://www.cnblogs.com/Angel-Demon/p/10389201.html

主要内容:本文详细介绍了一种QRBiLSTM(分位数回归双向长短期记忆网络)的时间序列区间预测方法。首先介绍了项目背景以及模型的优势,比如能够有效利用双向的信息,并对未来的趋势上限和下限做出估计。接着从数据生成出发讲述了具体的代码操作过程:数据预处理,搭建模型,进行训练,并最终可视化预测结果与计算分位数回归的边界线。提供的示例代码可以完全运行并且包含了数据生成环节,便于新手快速上手,深入学习。此外还指出了模型未来发展的方向,例如加入额外的输入特性和改善超参数配置等途径提高模型的表现。文中强调了时间序列的标准化和平稳检验,在样本划分阶段需要按时间序列顺序进行划分,并在训练阶段采取合适的手段预防过度拟合发生。 适合人群:对于希望学习和应用双向长短时记忆网络解决时序数据预测的初学者和具有一定基础的研究人员。尤其适用于有金融数据分析需求、需要做多一步或多步预测任务的从业者。 使用场景及目标:应用于金融市场波动预报、天气状况变化预测或是物流管理等多个领域内的决策支持。主要目的在于不仅能够提供精确的数值预计还能描绘出相应的区间概率图以增强结论置信程度。 补充说明:本教程通过一个由正弦信号加白噪构造而成的简单实例来指导大家理解和执行QRBiLSTM流程的所有关键步骤,这既方便于初学者跟踪学习,又有利于专业人士作为现有系统的补充参考工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值