zoukankan      html  css  js  c++  java
  • 洛谷P4364 IIIDX

    题意:给定n个数和k,把n个数排成序列,满足ai >= ai/k,并使之字典序最大。

    解:毒瘤线段树贪心...

    以i/k为i的父亲构树。

    当这n个数不同的时候,直接后序遍历贪心即可。

    正解神奇的一批......

    从大到小排序并建线段树,维护fi为每个数自己及左边(大于等于它)之中有多少个数能选。

    假设我们i位置选了x,i的siz是s,那么[x, n]的f值要减去s,表示其中s个数被i的子树预定了。

    然后当我们算i的儿子的时候,就要把[x, n]的f加上siz son i,避免给自己预定的自己反而不能选。

    如何确定x?要尽量大,所以在线段树上往左找。

    一个数能被选,需要他的f值不小于siz i

    这样我们发现样例都过不了。之前加[x, n]的时候,[1, x-1]没有改变,但是这是不对的,简略来说就是右边对左边有影响。

    如果我们选了一个位置,但是右边有一个的f值却小于siz i了。那么你想啊,能选大的不能选小的,显然有问题。就是那个小的的左边都不够,你更靠左怎么可能够...

    于是要求[x, n]的f全部不小于siz i。

    选出来的x对应的值可能有多个,选择最右的那个。是因为这样有决策包容性?

    还是有一点不懂,比如为什么不需要标记一个位置已被选,不怕选重复了吗?

      1 #include <cstdio>
      2 #include <algorithm>
      3 
      4 const int N = 500010;
      5 
      6 int n, a[N], siz[N], pos[N], fa[N], ans[N], X[N], xx;
      7 double k;
      8 int tag[N * 4], small[N * 4];
      9 
     10 inline void pushdown(int o) {
     11     if(tag[o]) {
     12         tag[o << 1] += tag[o];
     13         tag[o << 1 | 1] += tag[o];
     14         small[o << 1] += tag[o];
     15         small[o << 1 | 1] += tag[o];
     16         tag[o] = 0;
     17     }
     18     return;
     19 }
     20 
     21 inline void add(int L, int R, int v, int l, int r, int o) {
     22     //printf("add : %d %d %d %d %d 
    ", L, R, v, l, r);
     23     if(L <= l && r <= R) {
     24         small[o] += v;
     25         tag[o] += v;
     26         return;
     27     }
     28     int mid = (l + r) >> 1;
     29     pushdown(o);
     30     if(L <= mid) {
     31         add(L, R, v, l, mid, o << 1);
     32     }
     33     if(mid < R) {
     34         add(L, R, v, mid + 1, r, o << 1 | 1);
     35     }
     36     small[o] = std::min(small[o << 1], small[o << 1 | 1]);
     37     //printf("min %d %d  = %d 
    ", l, r, small[o]);
     38     return;
     39 }
     40 
     41 inline int getpos(int k, int l, int r, int o) {
     42     //printf("ask %d %d %d 
    ", k, l, r);
     43     if(l == r) {
     44         return small[o] < k ? a[r + 1] : a[r];
     45     }
     46     int mid = (l + r) >> 1;
     47     pushdown(o);
     48     //printf("%d >= %d 
    ", small[o << 1 | 1], k);
     49     if(small[o << 1 | 1] >= k) {
     50         return getpos(k, l, mid, o << 1);
     51     }
     52     else {
     53         return getpos(k, mid + 1, r, o << 1 | 1);
     54     }
     55 }
     56 
     57 void build(int l, int r, int o) {
     58     if(l == r) {
     59         small[o] = r;
     60         return;
     61     }
     62     int mid = (l + r) >> 1;
     63     build(l, mid, o << 1);
     64     build(mid + 1, r, o << 1 | 1);
     65     small[o] = std::min(small[o << 1], small[o << 1 | 1]);
     66     return;
     67 }
     68 
     69 int main() {
     70     scanf("%d%lf", &n, &k);
     71     for(int i = 1; i <= n; i++) {
     72         scanf("%d", &a[i]);
     73         X[i] = a[i];
     74     }
     75     std::sort(a + 1, a + n + 1);
     76     std::sort(X + 1, X + n + 1);
     77     std::reverse(a + 1, a + n + 1);
     78     int xx = std::unique(X + 1, X + n + 1) - X - 1;
     79     for(int i = n; i >= 1; i--) {
     80         a[i] = std::lower_bound(X + 1, X + xx + 1, a[i]) - X;
     81         siz[i]++;
     82         fa[i] = (i / k);
     83         siz[fa[i]] += siz[i];
     84     }
     85 
     86     for(int i = 1; i <= n; i++) {
     87         pos[a[i]] = i;
     88     }
     89 
     90     build(1, n, 1);
     91 
     92     for(int i = 1; i <= n; i++) {
     93         // choose i
     94         if(fa[i]) {
     95             add(ans[fa[i]], n, siz[i], 1, n, 1);
     96         }
     97         int t = getpos(siz[i], 1, n, 1);
     98         //printf("i = %d  t = %d 
    ", i, t);
     99         t = pos[t]--;
    100         // i choose t
    101         ans[i] = t;
    102         //printf("fa = %d 
    ", fa[i]);
    103         add(t, n, -siz[i], 1, n, 1);
    104     }
    105 
    106     for(int i = 1; i <= n; i++) {
    107         printf("%d ", X[a[ans[i]]]);
    108     }
    109     return 0;
    110 }
    AC代码

    总之很神。

  • 相关阅读:
    基于Qt5的排序算法简单可视化
    中文简体数字转阿拉伯数字
    Visual Studio Emulator For Android无法装载APK
    使用iFrame动态加载Application Cache
    Docker入门第五章
    Docker入门第四章
    Docker入门第三章
    Docker入门第二章
    Docker入门第一章
    Java7新特性
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10399984.html
Copyright © 2011-2022 走看看