【LOJ】#2265. 「CTSC2017」最长上升子序列

题解

点了一个新技能叫杨表(事实上集训的时候听过,但是一直不会

这道题就是让我们找到k个不上升子序列,要求长度加和最大

我们用杨表去维护,但是由于杨表的行数可能是n的,复杂度会炸
我们只维护前\(\sqrt{n}\)
有个结论是把杨表排序方式改过来那么我们会得到杨表的转置,我们发现我们只需要求一些列的和就好了,这个转置后的也只需要维护到\(\sqrt{n}\)行即可

二分找每行的插入位置即可\(O(n\sqrt{n} \log n + k \sqrt{n})\)

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 50005
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
	if(c == '-') f = -1;
	c = getchar();
    }
    while(c >= '0' && c <= '9') {
	res = res * 10 + c - '0';
	c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
int N,Q,S;
int b[MAXN],ans[200005],tr[MAXN];
struct qry_node {
    int pos,id,k;
    friend bool operator < (const qry_node &a,const qry_node &b) {return a.pos < b.pos;}
}qry[200005];
int lowbit(int x) {return x & (-x);}
void Ins(int x,int v) {
    while(x <= N) {
	tr[x] += v;
	x += lowbit(x);
    }
}
int Query(int x) {
    int res = 0;
    while(x > 0) {
	res += tr[x];
	x -= lowbit(x);
    }
    return res;
}
struct YoungTable {
    int a[245][MAXN];
    int findA(int x,int y,int v) {
	if(y == 0) return 0;
	int L = 0,R = y;
	while(L < R) {
	    int mid = (L + R + 1) >> 1;
	    if(a[x][mid] >= v) L = mid;
	    else R = mid - 1;
	}
	return L;
    }
    int findB(int x,int y,int v) {
	if(y == 0) return 0;
	int L = 0,R = y;
	while(L < R) {
	    int mid = (L + R + 1) >> 1;
	    if(a[x][mid] < v) L = mid;
	    else R = mid - 1;
	}
	return L;
    }
    void Insert(int x,int y,int v,bool on) {
	if(x > S) return;
	y = min(a[x][0],y);
	if(!on) y = findA(x,y,v);
	else y = findB(x,y,v);
	++y;
	if(a[x][y] == 0) {
	    a[x][y] = v;++a[x][0];
	    if(on) Ins(y,1);
	}
	else {
	    int t = a[x][y];a[x][y] = v;
	    Insert(x + 1,y,t,on);
	}
    }
}A,B;
int Calc(int k) {
    int res = 0;
    if(k <= S) {
	for(int i = 1 ; i <= k ; ++i) res += A.a[i][0];
    }
    else {
	for(int i = 1 ; i <= S ; ++i) res += A.a[i][0];
	res += Query(k) - Query(S);
    }
    return res;
}
void Solve() {
    read(N);read(Q);
    S = sqrt(N);
    for(int i = 1 ; i <= N ; ++i) read(b[i]);
    for(int i = 1 ; i <= Q ; ++i) {
	qry[i].id = i;read(qry[i].pos);read(qry[i].k);
    }
    sort(qry + 1,qry + Q + 1);
    int p = 1;
    for(int i = 1 ; i <= N ; ++i) {
	A.Insert(1,N + 1,b[i],0);B.Insert(1,N + 1,b[i],1);
	while(p <= Q && qry[p].pos == i) {
	    ans[qry[p].id] = Calc(qry[p].k);
	    ++p;
	}
    }
    for(int i = 1 ; i <= Q ; ++i) {out(ans[i]);enter;}
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}
posted @ 2018-10-18 16:37  sigongzi  阅读(871)  评论(0编辑  收藏  举报