UOJ#301. 【CTSC2017】最长上升子序列(杨氏矩阵)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/82501437

传送门

题解:

根据Dilworth定理,最小链覆盖=最长反链。 问题转化为求 k 个最小不上升序列能覆盖的最大数的个数。

利用杨氏矩阵,我们可以轻松得到这个值。 不过注意杨氏矩阵的插入是 O ( n ) 的,这时候有个定理,就是把杨氏矩阵维护东西的大小比较方式改变一下,会得到置换原矩阵后的矩阵。

于是我们原矩阵只维护 O ( n ) 行,查询前 k 行时我们只查询前 n 行,剩下的就是置换矩阵的某一列。 发现置换矩阵也只用维护前 n 行,于是结合二分即可做到 O ( n n log n + q log n ) 的复杂度。不过不好卡,直接暴力插入杨氏矩阵也可以通过。

#include <bits/stdc++.h>
using namespace std;

const int RLEN=1<<18|1;
inline char nc() {
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
    char ch=nc(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
    return i*f;
}
inline void W(int x) {
    static int buf[50];
    if(!x) {putchar('0'); return;}
    if(x<0) {putchar('-'); x=-x;}
    while(x) {buf[++buf[0]]=x%10; x/=10;}
    while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}

const int N=50005, S=sqrt(N)+3;

int n,Q,a[N],ans[N*4];
struct qry {
    int pos, k, id;
    friend inline bool operator <(const qry &a,const qry &b) {return a.pos<b.pos;}
} q[N*4];

namespace A {
    int a[S][N];
    inline void ins(int v,int x=1,int y=n) {
        if(x>=S) return;
        y=min(y,a[x][0]);
        while(y && a[x][y]<v) --y; ++y;
        if(!a[x][y]) {
            ++a[x][0]; a[x][y]=v;
        } else {
            ins(a[x][y],x+1,y);
            a[x][y]=v;
        }
    }
}
namespace B {
    int a[S][N], len[N];
    inline void inc(int pos) {for(int i=pos;i<=n;i+=(i&(-i))) ++len[i];}
    inline int ask(int pos) {int rs=0; for(int i=pos;i;i-=(i&(-i))) rs+=len[i]; return rs;}
    inline int ask(int l,int r) {return ask(r)-ask(l-1);}
    inline void ins(int v,int x=1,int y=n) {
        if(x>=S) return;
        y=min(y,a[x][0]);
        while(y && a[x][y]>=v) --y; ++y;
        if(!a[x][y]) {
            ++a[x][0]; a[x][y]=v;   
            inc(y);
        } else {
            ins(a[x][y],x+1,y);
            a[x][y]=v;
        }
    }
}

inline int qry(int k,int rs=0) {
    if(k<S) {
        for(int i=1;i<=k && A::a[i][0];i++) rs+=A::a[i][0];
    } else {
        for(int i=1;i<S;i++) rs+=A::a[i][0];
        rs+=B::ask(S,k);
    } return rs;
}
int main() {
    n=rd(), Q=rd();
    for(int i=1;i<=n;i++) a[i]=rd();
    for(int i=1;i<=Q;i++) q[i].pos=rd(), q[i].k=rd(), q[i].id=i;
    sort(q+1,q+Q+1);
    for(int i=1,j=1;i<=n && j<=Q;++i) {
        A::ins(a[i]); B::ins(a[i]);
        while(j<=Q && q[j].pos==i) ans[q[j].id]=qry(q[j].k), ++j;
    }
    for(int i=1;i<=Q;i++) W(ans[i]), putchar('\n');
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/82501437