Codeforces 786C Till I Collapse[主席树][二分]
来源:互联网 发布:网络教育专科怎么报名 编辑:程序博客网 时间:2024/06/05 03:13
题意:给你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的位置,Next[i]表示在i位置的数下一次出现在哪个位置。
以下是代码:
#include<iostream>#include<cstdio>#include<algorithm>#include<queue>#include<map>#include<set>#include<stack>#include<cstring>#include<string>#include<vector>//#include<unordered_set>//#include<unordered_map>#include<cmath>using namespace std;#define ull unsigned long long#define ll long long#define lson l,mid,id<<1#define rson mid+1,r,id<<1|1typedef pair<int, int>pii;typedef pair<ll, ll>pll;typedef pair<double, double>pdd;const double eps = 1e-6;const int MAXN = 100005;const int MAXM = 5005;const ll LINF = 0x3f3f3f3f3f3f3f3f;const int INF = 0x3f3f3f3f;const int MOD = 1000000007;const double FINF = 1e18;struct {int lc, rc, sum;}st[MAXN * 100];int n, ed[MAXN], Next[MAXN];int rt[MAXN], a[MAXN],cnt, ans[MAXN];void update(int l, int r, int &x, int y, int pos , int val) {st[++cnt] = st[y], st[cnt].sum+=val, x = cnt;if (l == r)return;int mid = (l + r) / 2;if (pos <= mid)update(l, mid, st[x].lc, st[y].lc, pos, val);else update(mid + 1, r, st[x].rc, st[y].rc, pos, val);}int find(int l, int r, int x, int pos){if (l == r)return l;int mid = (l + r) >> 1;if (st[st[x].lc].sum >= pos)return find(l, mid, st[x].lc, pos);else return find(mid + 1, r, st[x].rc, pos - st[st[x].lc].sum);}int main(){memset(ans, 0, sizeof(ans));scanf("%d", &n);for (int i = 1; i <= n; i++){scanf("%d", &a[i]);ed[i] = n + 1;}for (int i = n; i >= 1; --i){Next[i] = ed[a[i]];ed[a[i]] = i;}for (int i = 1; i <= n; ++i)update(1, n + 1, rt[1], rt[1], ed[i], 1);for (int i = 2; i <= n; ++i){update(1, n + 1, rt[i], rt[i - 1], i - 1, -1);update(1, n + 1, rt[i], rt[i], Next[i - 1], 1);}int l, r, L, R, mid, tmp;for (int i = 1; i <= n; ++i){int now = 1;while (now <= n){now = find(1, n + 1, rt[now], i + 1);ans[i]++;}}for (int i = 1; i <= n; ++i)cout << ans[i] << " ";}/*51 3 4 3 3*/
0 0
- Codeforces 786C Till I Collapse[主席树][二分]
- Codeforces 787E Till I Collapse 主席树+二分
- Codeforces-786C-Till I Collapse(二分剪枝)
- codeforces 786c Till I Collapse
- Codeforces Round #406 (Div. 1) C. Till I Collapse(主席树)
- Codeforces Round #406 (Div. 1) C. Till I Collapse(可持久化线段树)
- Codeforces Round #406 (Div. 2) E. Till I Collapse
- 【题解】codeforces786C Till I Collapse
- 【Codeforces 597C】 Subsequences - DP 主席树
- bzoj2653 -- 二分+主席树
- Codeforces 458C Elections 贿赂选票抢主席! 线段树
- codeforces 853c (关于矩形的主席树)
- 【暴力讨论+主席树】Codeforces 853C Boredom
- Keep alive till I die
- bzoj2653 Middle 二分&主席树
- HDU 5915 (二分 主席树)
- bzoj 2653 二分+主席树
- [主席树+二分] BZOJ2653: middle
- 搭建Python Web RestApi
- ListView常见问题一
- B. Chris and Magic Square
- 小心使用replicate_do_db和replicate_ignore_db
- C/C++_log2000_explicit关键字
- Codeforces 786C Till I Collapse[主席树][二分]
- 5.vue.js实例:多维数组实例
- 【Java基础】线程笔记——显式锁Lock和ReentrantLock
- vecor/list/dequeue
- 数组内字符的全排列算法
- TensorFlow 深度学习笔记 TensorFlow实现与优化深度神经网络
- Java多线程wait()、notify()小demo
- Linux防火墙
- pat 直捣黄龙 (Dijkstra)