Hdu 3564 Another LIS 线段树+LIS

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1361    Accepted Submission(s): 492


Problem Description
There is a sequence firstly empty. We begin to add number from 1 to N to the sequence, and every time we just add a single number to the sequence at a specific position. Now, we want to know length of the LIS (Longest Increasing Subsequence) after every time's add.
 
Input
An integer T (T <= 10), indicating there are T test cases.
For every test case, an integer N (1 <= N <= 100000) comes first, then there are N numbers, the k-th number Xk means that we add number k at position Xk (0 <= Xk <= k-1).See hint for more details.
 
Output
For the k-th test case, first output "Case #k:" in a separate line, then followed N lines indicating the answer. Output a blank line after every test case.
 
Sample Input
1
3
0 0 2
 
Sample Output
Case #1:
1
1
2
Hint
In the sample, we add three numbers to the sequence, and form three sequences. a. 1 b. 2 1 c. 2 1 3
 
Author
standy
 
Source
 
思路:由于是从大到小插值的,那么我们只需要知道最终的序列,再对其求一遍LIS即可。可以用线段树求最终的序列,从后往前考虑,一开始有n个空位,对于每个数的插入位置a[i],其应该放在从左往右的第a[i]个空格,放完数后该空格被占用。该问题相当于给出n个数,多次操作,找出第k1个数后,将该数删去,继续找第k2个数。。。
#include <bits/stdc++.h>
using namespace std;
const int N = 100000 + 5;
#define lson rt << 1, l, m
#define rson rt <<1|1, m + 1, r

int num[N << 2];
int a[N], pos[N], ans[N], res[N], n;
void build(int rt, int l, int r) {
    num[rt] = r - l + 1;
    if(l == r) return ;
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
}
void update(int rt, int l, int r, int k, int v) {
    if(l == r) {
        pos[l] = v;
        num[rt] = 0;
        return;
    }
    int m = (l + r) >> 1;
    if(k > num[rt << 1]) update(rson, k - num[rt << 1], v);
    else                 update(lson, k, v);
    num[rt] = num[rt << 1] + num[rt << 1|1];
}
int LIS[N], len;
void solve() {
    len = 1;
    LIS[0] = 0;
    for(int i = 1; i <= n; ++i) {
        int p = upper_bound(LIS, LIS + len, pos[i]) - LIS - 1;
        LIS[p + 1] = pos[i];
        ans[i] = p + 1;
        if(p + 1 == len) len++;
    }
}
int main() {
   // freopen("in.txt", "r", stdin);
    int _, cas = 1; scanf("%d", &_);
    while(_ --) {
        scanf("%d", &n);
        build(1, 1, n);
       // puts("-----BUG-----");

        for(int i = 1; i <= n; ++i) { scanf("%d", a + i); a[i]++; }
        for(int i = n; i >= 1; --i) update(1, 1, n, a[i], i);
        solve();
        for(int i = 1; i <= n; ++i) res[ pos[i] ] = ans[i];
        for(int i = 2; i <= n; ++i) res[i] = max(res[i], res[i - 1]);
        printf("Case #%d:
", cas++);
        for(int i = 1; i <= n; ++i) printf("%d
", res[i]);
        puts("");
    }
}
View Code
原文地址:https://www.cnblogs.com/orchidzjl/p/5487770.html