zoukankan      html  css  js  c++  java
  • 2021 ICPC 第一场网络赛 A Busiest Computing NodesA Busiest Computing Nodes

    题目:A Busiest Computing Nodes(The 2021 ICPC Asia Regionals Online Contest)

    1.计算机的维护:

    我们维护一个线段树在计算机的状态上,然后按照时间来改变计算机的状态,初始所有值为0。

    在一个固定的时间,当一个计算机被占用时,我们就将计算机的状态置为1,即不可用状态,并且线段树每个结点维护当前结点的子树中是否存在状态为0的结点,就可以知道这个结点以下是否有可用结点。

    2.请求的处理:

    我们再维护一个 (vector<int> time[]) ;的序列,其中第 (time[i]) 表示在时刻 (i) 重新回归可用状态的计算机编号。当我们时间走到某一个 (time[i]) 时,遍历 (time[i])(vector) 序列,将所有在 (time[i]) 重新回归可用状态的计算机更新为0状态,即可用状态。

    对于单个请求,设我们需要占用得计算机为 (idx) 那么我们就需要在 ([idx , k-1]) 的区间内查询最左侧的状态0的计算计编号,我们只需要按照先左子树,再右子树的顺序查询即可。如果左子树存在状态为 (0) 的结点,那么递归查询左子树,并返回结点的 (idx) ,否则递归查询右子树。

    如果我们在 ([idx , k-1]) 范围查不到,那么我们就在 ([0 , k-1]) 范围内查询最左状态0的计算机编号。查询方法同上。

    如果还未查到,说明不存在可用状态的计算机,直接继续处理下一个查询。

    如果查到了,那么就在线段树中将该计算机状态置 (1) ,即不可用状态,再在 (time[当前request处理完成时间]) 的vector中加入该计算机。

    3.时间的处理:

    时间节点只会出现 $arrive Time $和 (arriveTime+processTime) 之间的比较,没有其他的加减乘除,故直接离散化即可。总共不同的时间最多为 (2*n) 种不同的时间, (time[]) 显然开的下。

    4.时间复杂度分析:

    我们从线段树中每次置 0 或 1 的复杂度为 (log_{2}(k)),置0的次数显然小于n,每一次置1都是要先将该计算机置 0 ,所以置 1 的次数小于置 0 的次数。故总共在线段树上操作次数不超过 2n 。所以最后下来复杂度大致是 (2nlog_{2}(k))

    5.空间复杂度分析:

    线段树4倍k,(vector<int> time[]) 在最多时,所有点加入其中,不超过k个,即使有空vector占用,但时间的总数量不超过2*n个。故不会超空间。

    6.代码:(自己按照需求手搓的魔改线段树)

    #include<iostream>
    #include<map>
    #include<unordered_map>
    //#include<map>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    using namespace std;
    
    typedef long long ll;
    const int maxn = 1e5 + 50;
    
    //super tree
    struct node {
        int l, r;
        int sum;
        int lson, rson;
    } tree[maxn * 4];
    int tot = 1;
    int rrr;
    void build(int now, int l, int r, int len) {
        //cout << l << " " << r << endl;
        //cout << len << endl;
        tree[now].l = l;
        tree[now].r = r;
        tree[now].sum = 0;
        if (l == r) {
            tree[now].lson = tree[now].rson = -1;
            return;
        }
        tree[now].lson = tot++;
        tree[now].rson = tot++;
        build(tree[now].lson, l, l + len - 1, len / 2);
        build(tree[now].rson, r - len + 1, r, len / 2);
    }
    int getIdx(int idx, int now) {
        if (tree[now].l > rrr)return -1;
        if (tree[now].l == tree[now].r) {
            tree[now].sum = 1;
            return tree[now].l;
        }
        int ret = -1;
        int lson = tree[now].lson, rson = tree[now].rson;
        if (tree[lson].sum == 0 && tree[lson].r >= idx) {
            ret = getIdx(idx, tree[now].lson);
        }
        if (ret == -1 && tree[rson].sum == 0 && tree[rson].l <= rrr) {
            ret = getIdx(idx, tree[now].rson);
        }
        if (tree[lson].sum == 1 && tree[rson].sum == 1) {
            tree[now].sum = 1;
        }
        return ret;
    }
    void add(int idx, int now) {
        int lson = tree[now].lson, rson = tree[now].rson;
        if (lson == -1) {
            tree[now].sum = 0;
            return;
        }
        if (tree[lson].r < idx) {
            add(idx, rson);
        } else {
            add(idx, lson);
        }
        if (tree[lson].sum == 0 || tree[rson].sum == 0) {
            tree[now].sum = 0;
        }
    }
    
    
    map<ll, int> ck;
    vector<int> timeadd[2 * maxn];
    int num[2 * maxn], numtot, cktot;
    struct proc {
        int atime, stime;
    } info[maxn];
    int cnt[maxn];
    int ans[maxn], anstot;
    int main() {
        ios::sync_with_stdio(false);
        int k, n;
        int a, b;
        //freopen("1.in", "r", stdin);
        scanf("%d%d", &k, &n);
        rrr = k;
        int len = 1;
        while (len < k)len *= 2;
        build(0, 0, len - 1, len / 2);
    
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &a, &b);
            info[i].atime = a;
            info[i].stime = a + b;
            num[numtot++] = a;
            num[numtot++] = a + b;
        }
    
        sort(num, num + numtot);
        int pre = -1;
        for (int i = 0; i < numtot; i++) {
            if (num[i] != pre) {
                ck[num[i]] = cktot++;
            }
        }
        for (int i = 0; i < n; i++) {
            info[i].atime = ck[info[i].atime];
            info[i].stime = ck[info[i].stime];
            //cout << info[i].atime << " " << info[i].stime << endl;
        }
        int now = 0;
        for (int i = 0; i < n; i++) {
            while (now <= info[i].atime) {
                for (int j = 0; j < timeadd[now].size(); j++) {
                    add(timeadd[now][j], 0);
                }
                now++;
            }
            timeadd[info[i].atime].clear();
            if (tree[0].sum == 1) {
                continue;
            }
            int idx = getIdx(i % k, 0);
            if (idx == -1) {
                idx = getIdx(0, 0);
            }
            timeadd[info[i].stime].push_back(idx);
            //cout << idx << endl;
            cnt[idx]++;
    
        }
    
        int maxx = 0;
        for (int i = 0; i < k; i++) {
            if (cnt[i] == maxx) {
                ans[anstot++] = i;
            } else if (cnt[i] > maxx) {
                anstot = 0;
                ans[anstot++] = i;
                maxx = cnt[i];
            }
        }
        //cout<<maxx<<" "<<anstot<<endl;
        // << "ans:" << endl;
        for (int i = 0; i < anstot; i++) {
            if (i)cout << " ";
            cout << ans[i];
        } cout << endl;
        return 0;
    };
    


    跑的飞快。

  • 相关阅读:
    哈夫曼树
    顺序栈和链栈
    线性表(二) 单链表的增删改查及源码 (修改)
    线性表(二):单链表的增删改查及源码
    线性表(一):顺序表的增删改查及源码
    从头学数据结构--跟随浙大陈越姥姥的步伐
    Java学习笔记--scanner获取键盘输入
    关于方法、变量、类等命名规范
    Java学习笔记--类型自动转换、强制类型转换、溢出
    java学习笔记--重载
  • 原文地址:https://www.cnblogs.com/greenpepper/p/15315473.html
Copyright © 2011-2022 走看看