九省联考2018D1T2 IIIDX

链接

很容易发现,歌曲间的关系构成了一棵树,于是O(n)的贪心算法也就是显然的。

但是我们对贪心带来的55~60分不满意,鉴于这个题是个nlogn范围,所以还是用数据结构吧。

很容易发现,题目给出的n首歌的难度顺序不会影响最终答案,所以首先对这个难度值从大到小排序

不过树还是要构造的,接下来预处理出每个节点的子树大小

之后,每次找一个最靠左的位置,使得这个位置左边足够放下当前节点的子树。如果有多个值相同,就放到最右边的值那里。

上面是最关键的一句话,想到这里,就突破了贪心狭隘的思路,并取得了成功的一半。

利用线段树维护每个位置左边(包括自身)还能放多大的子树,初始为1, 2, 3 ... n。

记录一个same数组表示与当前数字相同的值最靠右边的位置,然后每次查找时在线段树上二分,之后再放到最右边那里,记为pos。

放完之后,更新线段树,因为放了一棵树,所以使得pos位置和pos右边的所有位置左边的空间减少了当前节点的子树大小,就对线段树进行区间减操作。

时间复杂度O(nlogn)。

#include <iostream>
#include <algorithm>
#include <cstdio>

const int maxn = 5e5 + 7;

using namespace std;

int a[maxn];
int fa[maxn];
int ans[maxn];
int size[maxn];
int same[maxn];
int st[maxn << 2]; //线段树维护最小值
int add[maxn << 2];

inline int read()
{
    int X = 0; char ch = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') X = (X << 3) + (X << 1) + ch - '0', ch = getchar();
    return X;
}

inline bool cmp(int x, int y)
{
    return x > y;
}

inline void pushup(int rt)
{
    st[rt] = min(st[rt << 1], st[rt << 1 | 1]);
}

void build(int l, int r, int rt)
{
    if (l == r) {
        st[rt] = l; //初始为1 -> n的序列
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    pushup(rt);
}

inline void pushdown(int rt)
{
    if (add[rt]) {
        st[rt << 1] += add[rt];
        st[rt << 1 | 1] += add[rt];
        add[rt << 1] += add[rt];
        add[rt << 1 | 1] += add[rt];
        add[rt] = 0;
    }
}

void update(int x, int y, int z, int l, int r, int rt)
{
    if (l >= x && r <= y) {
        st[rt] += z;
        add[rt] += z;
        return;
    }
    pushdown(rt);
    int mid = (l + r) >> 1;
    if (x <= mid) update(x, y, z, l, mid, rt << 1);
    if (y > mid) update(x, y, z, mid + 1, r, rt << 1 | 1);
    pushup(rt);
}

int find(int x, int l, int r, int rt) //线段树中的二分查找
{
    if (l == r) return l + (st[rt] < x);
    pushdown(rt);
    int ls = rt << 1, rs = ls | 1, mid = (l + r) >> 1;
    if (x <= st[rs]) return find(x, l, mid, ls);
    return find(x, mid + 1, r, rs);
}

int main(void)
{
    int n = read();
    double k;
    cin >> k;
    for (register int i = 1; i <= n; i++) a[i] = read();
    sort(a+1, a+n+1, cmp);
    for (register int i = n-1; i; i--) if (a[i] == a[i+1]) same[i] = same[i+1] + 1; //每个数与它右边连续几个数相同
    for (register int i = 1; i <= n; i++) fa[i] = int(i / k), size[i] = 1;
    for (register int i = n; i; i--) size[fa[i]] += size[i]; //预处理子树大小
    build(1, n, 1);
    for (register int i = 1; i <= n; i++) {
        if (fa[i] != fa[i-1]) update(ans[fa[i]], n, size[fa[i]] - 1, 1, n, 1); //维护单调性以保证二分查找的正确性
        int pos = find(size[i], 1, n, 1);
        pos += same[pos]; //传送到最右边相同值位置
        same[pos]++; //因为一个位置不能重复使用多次,所以第一遍传送到最右值之后,第二遍要传送到次右值,以此类推
        pos -= same[pos] - 1; //往回跳
        ans[i] = pos;
        update(pos, n, -size[i], 1, n, 1); //更新
    }
    for (register int i = 1; i <= n; i++) printf("%d ", a[ans[i]]);
    
    return 0;
}

### 回答1: 黄河九省地图数据Shp是一种包含九个省份的地理信息系统文件格式,可以在各种GIS软件中使用。这些九个省份包括青海、甘肃、宁夏、内蒙古、陕西、山西、河南、山东和河北。该地图数据Shp覆盖了全部黄河流域,以黄河为中心,包括了黄河流域内的山脉、河流、湖泊、城市、道路等地理要素。使用这个地图数据Shp可以提供各种黄河流域的地理信息分析与处理,如水文、水资源、水环境、地质灾害、城市规划、交通等领域。 该地图数据Shp由多个文件组成,其中包括.shp、.shx、.dbf等几个文件。其中.shp文件存储了地图数据几何图形信息,.shx文件存储了几何图形的索引信息,.dbf文件存储了属性数据信息。可以使用各种GIS软件打开这些文件,可以查看和编辑地图数据,进行地理信息分析和处理。 使用黄河九省地图数据Shp 可以进行各种有关黄河流域的地理信息分析和处理。例如,分析黄河流域内不同地区的地形、气候、土壤、地质等因素对河流水质、水量、水文周期以及水文气候等方面的影响。此外,还可以计算不同区域内的水资源量, 分析地区可能面临的水资源风险, 同时可以对水资源进行合理规划与管理。 总之,黄河九省地图数据Shp为黄河流域日常采集和分析水文资料提供了有力支持, 同时也可以支持城市建设和工程规划等方面的分析。因此,黄河九省地图数据Shp在黄河流域及周边地区的管理和规划等领域中具有广泛的应用前景。 ### 回答2: 黄河九省地图数据shp是一种包含有关中国黄河流域九个省份地理信息的数字地图文件。这些省份包括:青海、甘肃、宁夏、内蒙古、陕西、山西、河南、山东和河北。该地图文件将这些省份的边界和地理要素转换为几何图形,并将其存储在shp文件中,可实现对其进行空间分析和地图制作。 这个地图数据shp文件实用性很高,可以广泛应用于黄河流域相关的地理信息领域。例如,在自然资源管理方面,可以使用它来进行土地资源、水资源、气候资源和矿产资源的分析,以便有效管理和利用这些资源。而在交通运输、城市规划和环境保护方面,该文件可以用于路线规划、区域规划和环境监测,提高规划决策的准确性和精度。 此外,该地图数据shp文件可以应用在教育和科研领域,如地理信息系统、地理编码和遥感分析等方面,为学术研究和教学活动提供相关的数据支持和参考。总之,黄河九省地图数据shp文件是非常有价值的地理信息资源,对于研究和应用黄河流域相关的地理信息问题非常有帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值