KSGT - 2017.06.26 日常写题

小学期的第一天

上午,困走Linux的迷宫,熟悉了一遍终端,然而什么也没有记住

下午,恶补Java大作业,听教主吹水,深有感触,摇摆于强上大作业与缓学框架之间

晚上,放弃治疗,回归线段树怀抱

夜半,与嵩神交流,单方面碾压,任重而道远


对着教程呼啦呼啦的乱敲,没有章法,只为熟悉,具体的收获谈不上,只能说会用一些奇奇怪怪的编辑器了?然后,用起Ubuntu来不再同以前那般慌张了

犹记得初识PC^2时,小鹿乱撞,好似初恋,想上而不敢


假装学习一下午,开启1w8培训班之路

找到了对口的Java Web实训,然而被前提条件吓到,返回怒补各种框架,从此堕入知识黑洞

期间教主到访,办事间隙吹水赞叹,五年前大弟子发展迅速,超出想象,此番归来惊喜不断
其间更有,我已经培养出这些大弟子,够本了,只要他们隔三差五回来就好。虽为笑语,然亦可从中瞥见教主之得意

这个下午谈了很多,从各自公司变换,Team组成到回来对培养计划的意见,再到我个人的发展,天马行空。


换来换去,选来选去,终于费尽了精力,磨尽了精神。想起来还有个女神等着我约会,赶忙撂下键盘,奔赴现场。然而…这个女神有一点点复杂,懒癌晚期,弃坑而走。本着时刻假装学习的理念,学习了扫描线的写法,发现这只是一个小技巧,并不像原来想象的那样复杂

以我现阶段的认知来说,线段是永远只是线段树,它所能完成只是区间更新/查询,除此之外的任何功能都需要自己来完成,这种扫描线是,上回的二分外壳也是。
因而,线段树本身只完成区间的那部分工作,其他工作由其他部分完成。
队友说,重在建模,有一点模块化封装的意思。

我现在应该是初入线段树了,单点更新/区间更新/扫描线技巧都已经学习,然而对于,线段树的时间复杂度并不能很好的计算,因而做题是只求正确不求时限,超时再说;在构思阶段也无法对具体细节有很好的把握,总是要写到哪儿,编到哪儿,也就是无法把实现落于纸上,造成了编码后面需要大量Debug


现在以POJ 1177 说明存在的问题

对于这道题目,网络上的主流思路在于,离散化,一次扫描更新有扫描线平行的值,于其中更新中断的次数,也就是竖线的条数,完成最终更新

我认为,更新竖线条数的操作过于复杂,需要在segTree当中增加很多的变量,所以才用两次扫描更新,这种写法本应该是快速、简单,然而写孬了。

总共花费 19:00 - 22:30、 23:00 - 00:30、 7:30 - 9: 00

原因在于,建模时,我采用了左闭右闭区间,而这道题目点代表的真的是一个点,而不是一个块(区间?),就造成了,两个段之间的衔接出现了问题
我一直坚持使用CodeBlocks完成这道题目,而CodeBlocks的Debug功能不健全,所以一直没能发现,后面胡乱猜想数据才发现了问题。
教训,在样例出不来的时候,应该尝试简单一些的样例

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>

using namespace std;

const int maxn = 5000 + 10;

struct SegTree
{
    int l, r, cnt, sum;
}segTree[maxn << 2];

struct Line
{
    int a, b, h;
    int flag;
    Line(int a = 0, int b = 0, int h = 0, int flag = 0)
    {
        this->a = a, this->b = b, this->h = h, this->flag = flag;
    }
    bool operator < (const Line & rhs) const
    {
        return h < rhs.h || h == rhs.h && flag > rhs.flag;
    }
}hori_line[maxn << 1], vert_line[maxn << 1];

int cur1 = 0, cur2 = 0;
int new_ab[maxn << 1];

int depress(Line * line)
{
    vector<int> pool;
    for (int i = 0; i < cur1; i++)
    {
        pool.push_back(line[i].a);
        pool.push_back(line[i].b);
    }
    sort(pool.begin(), pool.end());
    pool.erase(unique(pool.begin(), pool.end()), pool.end());
    for (int i = 0; i < cur1; i++)
    {
        int cur = find(pool.begin(), pool.end(), line[i].a) - pool.begin();
        new_ab[cur] = line[i].a; line[i].a = cur;
        cur = find(pool.begin(), pool.end(), line[i].b) - pool.begin();
        new_ab[cur] = line[i].b; line[i].b = cur;
    }
    return pool.size() - 1;
}

void build(int k, int l, int r)
{
    segTree[k].l = l, segTree[k].r = r;
    segTree[k].cnt = 0;
    segTree[k].sum = 0;
    if (l + 1 >= r)
    {
        return;
    }
    int m = (l + r) >> 1;
    build(k << 1, l, m);
    build(k << 1 | 1, m, r);
}

void update(int k, int l, int r, int c)
{
    if (l > segTree[k].r || r < segTree[k].l) return;
    if (l <= segTree[k].l && segTree[k].r <= r)
    {
        segTree[k].cnt += c;
        if (segTree[k].cnt == 0)
            segTree[k].sum = segTree[k << 1].sum + segTree[k << 1 | 1].sum;
        else
            segTree[k].sum = new_ab[segTree[k].r] - new_ab[segTree[k].l];
        return;
    }
    if (segTree[k].l + 1 == segTree[k].r)
    {
        if (segTree[k].cnt == 0)
            segTree[k].sum = 0;
        else segTree[k].sum = new_ab[segTree[k].r] - new_ab[segTree[k].l];
        return;
    }
    update(k << 1, l, r, c);
    update(k << 1 | 1, l, r, c);
    if (segTree[k].cnt == 0)
        segTree[k].sum = segTree[k << 1].sum + segTree[k << 1 | 1].sum;
}

int solve(Line * line)
{
    int w = depress(line);
    build(1, 0, w);
    int res = 0, pre = 0;
    for (int i = 0; i < cur1; i++)
    {
        update(1, line[i].a, line[i].b, line[i].flag);
        int tem = segTree[1].sum;
        res += abs(pre - tem);
        pre = tem;
    }
    return res;
}

int main()
{
    int n; scanf("%d", &n);
    for (int i = 0; i < n; i++)
    {
        int xx1, yy1, xx2, yy2;
        scanf("%d%d%d%d", &xx1, &yy1, &xx2, &yy2);
        hori_line[cur1++] = Line(xx1, xx2, yy1, 1);
        hori_line[cur1++] = Line(xx1, xx2, yy2, -1);
        vert_line[cur2++] = Line(yy1, yy2, xx1, 1);
        vert_line[cur2++] = Line(yy1, yy2, xx2, -1);
    }
    sort(hori_line, hori_line + cur1);
    sort(vert_line, vert_line + cur2);
    int ans = 0;
    ans += solve(hori_line);
    //cout << ans << "++++++\n";
    ans += solve(vert_line);
    //cout << ans << "++++++\n";
    printf("%d\n", ans);

    return 0;
}

代码总体来说是合理的,逻辑简单而清晰

唯一不足之处在于,对sum进行更新,需要对cnt的不同情况进行分类,我没能把它单独放入一个函数中
我认为这个原因在于一开始没能想到这个细节,这个补充都是后面以及Debug的时候补上的,造成了逻辑有一点混乱


教主要我增加深度,正符合我试水操作系统的打算,咨询了一下嵩神,推荐了MIT课程,半夜翻墙出去,了解了大体情况,全英文课程,难度超群,紧张起来了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值