hdu 5324 Boring Class
来源:互联网 发布:java多泛型 编辑:程序博客网 时间:2024/06/07 14:30
题目描述:
给出两个序列L[i], R[i],求出最长的子序列v[i]满足:
v(1) ≥ 1, v(m) ≤ n,v(i) < v(i + 1). (for i from 1 to m - 1)
L(v(i)) ≥ L(v(i + 1)), R(v(i)) ≤ R(v(i + 1))(for i from 1 to m - 1)
n~1e5;
题解:
转化成求同时两个的最长单调不降子序列.
对于一维的求法:我们认为是(i, li)的单调不降子序列. 如果按照li从小到大的顺序往里面放,那么对于心将要往里放的i,来说, dp[i] = 维护的树状数组的从1到i的最大值. 同样,我们也可以按照i的顺序往里放,然后找<=li的树状数组中的最大值.
对于本题,其实是三维(i,li, ri). 如果我们按照i的顺序往里面放数,那么我们要找到的就是放在树套树结构中同时小于等于li和ri的最大的dp值.这样树套树的方法就有了:如果是两个线段树,那么先进入到1~li的区间的线段树节点来查询.进入节点内部之后: 要以ri为键值,来综合查找出一个最大的dp值.之后把线段树的节点有效值pushUp. 插入的话: 单点插入,一共是nlogn的空间复杂度.
独立于树套平衡树,我们还有一种更巧妙的方法来解这道题目.
对于(i,li,ri),想cdq分治.分治有什么好处呢? 只需要思考左端对右端的贡献就好,这样就会减少一维i!!!!!! 然后我们按照li的大小顺序把一个一个数放进去,用树状数组维护小于等于ri的最大的dp值,来+1作为dp[i]的值更新到树状数组中. 注意其中能够更新的只有mid+1到r的i, l到mid的i是不能更新的,只能放进去. 并且mid+1到r的是不能放到树状数组里面的. 和归并操作一样.这样完了之后再递归处理右边.
重点:
(1)想明白和以为的单调不降子序列的关系.以及熟练掌握用树状数组求单调不降子序列的思想,放进去的顺序的思维很好.
(2)用树状数组的思想来求3维不降子序列,考虑到树套树.
(3)三维减少一维的方法是分治.想明白cdq分治的影响部分.
代码:
////cdq分治.需要注意的地方很多#include <cstdio>#include <algorithm>#include <cstring>using namespace std;int n;struct node { int l, r, idx; friend bool operator < (node x, node y) { return x.l < y.l || (x.l == y.l && x.r < y.r) || (x.l == y.l && x.r == y.r && x.idx < y.idx); }}p[50010];int hs[50010];struct ans_node { int sum, idx; ans_node(int _sum = 0, int _pre = 0) { sum = _sum; idx = _pre; } friend bool operator < (ans_node x, ans_node y) { return x.sum < y.sum || x.sum == y.sum && x.idx > y.idx; }}C[50010], f[50010];int ans, ans_pos, prepre[50010];ans_node getMax(int x) { ans_node ret = ans_node(0, 0); while (x > 0) { ret = max(ret, C[x]); x -= x & -x; } return ret;}bool cmp(node x, node y) { return x.idx < y.idx;}void solve(int l, int r) { //printf("@#$%d %din\n", l, r); if (l == r) { if (f[l].sum == 0) { f[l].sum = 1; f[l].idx= l; } //printf("@#$%d %dout\n", l, r); return; } int mid = (l + r) >> 1; solve(mid + 1, r); int i = l, j = mid + 1; sort(p + l, p + mid + 1); sort(p + mid + 1, p + r + 1); int hs_len = 0; for (int i = mid + 1; i <= r; ++i) { hs[hs_len++] = p[i].r; } sort(hs, hs + hs_len); hs_len = unique(hs, hs + hs_len) - hs; for (int i = 0; i <= hs_len; ++i) { C[i] = 0; } for (int i = l; i <= mid; ++i) { int pos; while (j <= r && p[j].l <= p[i].l) { pos = lower_bound(hs, hs + hs_len, p[j].r) - hs + 1; while (pos <= hs_len) { C[pos] = max(C[pos], f[p[j].idx]); pos += pos & -pos; } j++; } pos = upper_bound(hs, hs + hs_len, p[i].r) - hs; ans_node max_nxt = getMax(pos), max_now = ans_node(f[p[i].idx].sum, prepre[p[i].idx]); max_nxt.sum++; if (max_now < max_nxt) {//注意,不能直接更新,因为以前的数可能会已经产生了影响. f[p[i].idx] = max_nxt; prepre[p[i].idx] = f[p[i].idx].idx; //printf("------%d %d\n", p[i].idx, f[p[i].idx].idx); f[p[i].idx].idx = p[i].idx; } } sort(p + l, p + mid + 1, cmp); solve(l, mid); //printf("@#$%d %dout\n", l, r);}int main() { //freopen("1009.in", "r", stdin); //freopen("out.txt", "w", stdout); while (~scanf("%d", &n)) { memset(f, 0, sizeof f); memset(prepre, 0, sizeof prepre); for (int i = 1; i <= n; ++i) { scanf("%d", &p[i].l); } for (int i = 1; i <= n; ++i) { scanf("%d", &p[i].r); p[i].r = -p[i].r; p[i].idx = i; } solve(1, n); int ans = 0, ans_pos = 1000010; for (int i = 1; i <= n; ++i) { if (f[i].sum > ans || f[i].sum == ans && f[i].idx < ans_pos) { ans = f[i].sum; ans_pos = f[i].idx; } } printf("%d\n", ans); printf("%d", ans_pos); for (int k = prepre[ans_pos]; k > 0; k = prepre[k]) { printf(" %d", k); } printf("\n"); } return 0;}///////////////树套平衡树. 还没学习= = 这是别人的代码. #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; const int maxn = 50010; struct Node{ Node *ch[2]; int r; int v; //第二维 int len; //长度 int idx; //下标 int mlen; //结点和结点左孩子右孩子里最大长度 int midx; //结点和结点左孩子右孩子里最大长度对应的下标 Node() {} Node(int v, int len, int idx):v(v),len(len),idx(idx),mlen(len),midx(idx) {ch[0] = ch[1] = NULL; r = rand();} int cmp(int x) const { if (x == v) return -1; return x < v ? 0 : 1; } void maintain(){ mlen = len; midx = idx; if (ch[0] != NULL && (ch[0]->mlen > mlen || (ch[0]->mlen == mlen && ch[0]->midx < midx))){ mlen = ch[0]->mlen; midx = ch[0]->midx; } if (ch[1] != NULL && (ch[1]->mlen > mlen || (ch[1]->mlen == mlen && ch[1]->midx < midx))){ mlen = ch[1]->mlen; midx = ch[1]->midx; } } }; bool findMax(Node* a, Node* b){ if (a->mlen < b->mlen || (a->mlen == b->mlen && a->midx > b->midx)){ *a = *b; return true; } return false; } namespace Treap{ int cntnode; Node node[maxn*10]; void init(){ cntnode = 0; } Node* newNode(int v, int len, int idx){ node[++cntnode] = Node(v, len, idx); return &node[cntnode]; } void rotate(Node* &o, int d){ Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o; o->maintain(); k->maintain(); o = k; } void insert(Node* &o, int v, int len, int idx){ if (o == NULL) o = newNode(v, len, idx); else { int d = o->cmp(v); if (d != -1){ insert(o->ch[d], v, len, idx); if (o->r < o->ch[d]->r) rotate(o, d^1); } else { if (len >= o->len){ o->len = len; o->idx = idx; } } } o->maintain(); } Node search(Node *o, int v){ if (o == NULL){ return Node(-1, 0, -1); } else{ Node re, tmp; if (o->v == v) { re = Node(o->v, o->len, o->idx); if (o->ch[1]){ findMax(&re, o->ch[1]); } } else if (o->v > v){ re = Node(o->v, o->len, o->idx); if (o->ch[1]){ findMax(&re, o->ch[1]); } if (o->ch[0]){ tmp = search(o->ch[0], v); findMax(&re, &tmp); } } else{ re = search(o->ch[1], v); } return re; } } } namespace BIT{ Node* fwt[maxn]; int N; void init(int n){ N = n; memset(fwt, 0, sizeof fwt); } void add(int v1, int v2, int len, int idx){ while(v1 < N){ Treap::insert(fwt[v1], v2, len, idx); v1 += (-v1)&v1; } } Node query(int v1, int v2){ Node re, tmp; re = Node(-1, 0, -1); while(v1 > 0){ tmp = Treap::search(fwt[v1], v2); findMax(&re, &tmp); v1 -= (-v1)&v1; } return re; } } struct Pe{ int L,R; int i; bool operator < (const Pe& rhs)const{ return L < rhs.L; } }; bool cmp(Pe a, Pe b){ return a.i < b.i; } int solo[maxn]; Pe pe[maxn];int pre[maxn]; void print(Node& a){ int id = a.midx; printf("%d\n", a.mlen); while(1){ printf("%d", id+1); if (pre[id] == -1){ break; } printf(" "); id = pre[id]; } printf("\n"); } int main(){ int n; while(scanf("%d", &n) != EOF){ for(int i=0;i<n;i++){ pe[i].i = i; scanf("%d", &pe[i].L); } for(int i=0;i<n;i++){ scanf("%d", &pe[i].R); } sort(pe, pe+n); int m = 0; solo[0] = ++m; for(int i=1;i<n;i++){ if (pe[i].L != pe[i-1].L){ solo[i] = ++m; } else{ solo[i] = solo[i-1]; } } for(int i=0;i<n;i++){ pe[i].L = solo[i]; } sort(pe, pe+n, cmp); BIT::init(m+1); Treap::init(); Node ans = Node(-1, 0, -1), tmp; for(int i=n-1;i>=0;i--){ tmp = BIT::query(pe[i].L, pe[i].R); pre[i] = tmp.midx; tmp.mlen = tmp.mlen + 1; tmp.midx = i; BIT::add(pe[i].L, pe[i].R, tmp.mlen, tmp.midx); findMax(&ans, &tmp); } print(ans); } return 0; }
- hdu 5324 Boring Class
- HDU 5324 Boring Class【cdq分治】
- hdu 5324 Boring Class (树套树)
- HDU 5324 Boring Class(CDQ分治)
- Hdu 5324 Boring Class (cdq分治)
- HDU 5324 Boring Class 树状数组套平衡树
- HDU 5324 Boring Class 树套树 或 CDQ分治
- hdu 5324 Boring Class cdq分治+树状数组+离散化
- HDU 5324 Boring Class(分治+树状数组)
- HDOJ 5324 Boring Class 树套树
- hdu 5324 Boring Class(15多校第三场1009)(cdq分治)
- 2015 Multi-University Training Contest 3(hdu 5324 - Boring Class)树套树
- hdu 5324 Boring Class(树状数组+笛卡尔树 | 树状数组+cdq分治)
- 【cdq分治】 HDOJ 5324 Boring Class
- hdu 5324 Boring Class 2015多校联合训练赛3 分治,最长不降子序列,最小字典序
- HDU5324 Boring Class
- HDU 2419 Boring Game
- hdu 3518 Boring counting
- 一个移动互联网自媒体的运营手记
- [深入理解Android卷一全文-第五章]深入理解常见类
- STL系列之一 deque双向队列
- linux下文件即文件夹操作
- DFS-POJ-1426-Find The Multiple
- hdu 5324 Boring Class
- 如何选择创业公司
- Linux Socket编程(不限Linux)
- 解决ScrollView嵌套ListView和GridView冲突的方法
- Shell中创建命令别名
- windows开启远程桌面
- zoj 3329 概率dp 环
- 简单md5加密
- hdu 2588 GCD---欧拉函数