zoukankan      html  css  js  c++  java
  • Codeforces Round #406 (Div. 1) C. Till I Collapse 主席树

    链接:

    http://codeforces.com/contest/786/problem/C

    题意:

    给你n个数,问最少能把这n个数分成连续的几段,且每段中不同的个数小于等于k个,输出k从1到n的答案。

    题解:

    我们知道i~(i,,,n)的不同数的个数肯定是递增的,所以对于每个i,我们可以通过二分得出一个最大的j使[i,j]中不同的数个数<=k。那么问题的关键在于,如何知道[i,j]这样一个区间中,不同的数的个数。

    我们可以利用主席树,以root[i]为顶点的线段树存的是,[i,n]中不同的数个数,对于每颗树,将每个第一次出现的数的位置 置为1,其他重复出现的位置 置为0。

    那么,对于每个k,刚开始我们位于root[1],二分找出值为k+1的位置r,ans[k]++,并将当前位置置成root[r],这样,我们面对的就是[r,n]这段数,直到r>n停止。

    ed[i]表示最先出现i的位置,nex[i]表示在i位置的数下一次出现在哪个位置。

    代码:

    31 struct Node { int l, r, sum; };
    32 int n, q;
    33 int a[MAXN], ed[MAXN], nex[MAXN];
    34 Node T[MAXN * 100];
    35 int rt[MAXN], cnt;
    36 int ans[MAXN];
    37 
    38 void update(int l, int r, int &x, int y, int pos, int val) {
    39     T[++cnt] = T[y], T[cnt].sum += val, x = cnt;
    40     if (l == r) return;
    41     int m = (l + r) >> 1;
    42     if (pos <= m) update(l, m, T[x].l, T[y].l, pos, val);
    43     else update(m + 1, r, T[x].r, T[y].r, pos, val);
    44 }
    45 
    46 int query(int l, int r, int x, int pos) {
    47     if (l == r) return l;
    48     int m = (l + r) >> 1;
    49     if (T[T[x].l].sum >= pos) return query(l, m, T[x].l, pos);
    50     else return query(m + 1, r, T[x].r, pos - T[T[x].l].sum);
    51 }
    52 
    53 int main() {
    54     ios::sync_with_stdio(false), cin.tie(0);
    55     cin >> n;
    56     rep(i, 1, n + 1) cin >> a[i], ed[i] = n + 1;
    57     per(i, 1, n + 1) nex[i] = ed[a[i]], ed[a[i]] = i;
    58     rep(i, 1, n + 1) update(1, n + 1, rt[1], rt[1], ed[i], 1);
    59     rep(i, 2, n + 1) {
    60         update(1, n + 1, rt[i], rt[i - 1], i - 1, -1);
    61         update(1, n + 1, rt[i], rt[i], nex[i - 1], 1);
    62     }
    63     rep(i, 1, n + 1) {
    64         int now = 1;
    65         while (now <= n) {
    66             now = query(1, n + 1, rt[now], i + 1);
    67             ans[i]++;
    68         }
    69     }
    70     rep(i, 1, n + 1) cout << ans[i] << ' ';
    71     cout << endl;
    72     return 0;
    73 }
  • 相关阅读:
    mysql 递归查询sql语句的实现
    Windows安装MySQL-5.6.13免安装版配置方法
    URL中的特殊字符处理
    Java序列化与反序列化
    url特殊字符转义及解决方法
    CentOs Mysql主从复制与读写分离
    java 转义特殊字符
    List列表中根据某一个字段,进行去重
    Spring定时任务的几种实现Quartz Timer task
    文件操作
  • 原文地址:https://www.cnblogs.com/baocong/p/7554553.html
Copyright © 2011-2022 走看看