P4093 [HEOI2016/TJOI2016]序列 (CDQ分治)

这道题的题意是求

j<i

aj<=a0[i]

a1[j]<=a[i]

这样的三维上升子序列

发现也是一道三维偏序问题,因此考虑用CDQ分治

对于第一位,我们按照惯例作为时间轴,但是这一次,查询要在前面,因为这里第一位是小于号,所以我们先查询再更改就不会弄到自己

我们将查询的权值设为a0[i],而修改的作为a[i],这样排序的时候就能知道把第二维排序掉了,当第二维相同,就是修改在前,因为这次可以查询相等的

对于第三维,使用树状数组,不同于之前的是,这里存的不是和,而是前面的最大值,不过用法是一样的

注意,清空树状数组的时候不能直接memset,因为这是O(N)的复杂度,而应该采用树状数组清空的方式,这样是log复杂度,所以这道题有双log,否则就超过复杂度了

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=1e9+7;
struct  node{
    int a,b,op,id;
}q[2*N],q0[2*N];
int a[N],a1[N],a0[N];
int tr[N];
int f[N];
int lowbit(int x){
    return x&-x;
}
void add(int x,int c,int op){
    int i;
    for(i=x;i<=1e5;i+=lowbit(i)){
        if(op==0)
            tr[i]=0;//清空树状数组
        else{
            tr[i]=max(tr[i],c);
        }
    }
}
int sum(int x){
    int res=0;
    int i;
    for(i=x;i;i-=lowbit(i)){
        res=max(res,tr[i]);
    }
    return res;
}
bool cmp(node a,node b){
    if(a.b==b.b)
        return a.op<b.op;
    return a.b<b.b;
}
void solve(int l,int r){
    if(l==r)
        return ;
    int mid=l+r>>1;
    solve(l,mid);
    sort(q+l,q+1+r,cmp);
    int i;
    for(i=l;i<=r;i++){
        int id=q[i].id;
        if(q[i].a<=mid&&q[i].op==1)
            add(a1[id],f[id],1);
        if(q[i].a>=mid+1&&q[i].op==2)
            f[id]=max(f[id],sum(a[id])+1);
    }
    for(i=l;i<=r;i++){
        int id=q[i].id;
        if(q[i].a<=mid&&q[i].op==1)
            add(a1[id],f[id],0);
    }
    for(i=l;i<=r;i++)
        q[i]=q0[i];
    solve(mid+1,r);
}
int main(){
    int n,m;
    cin>>n>>m;
    int i;
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a1[i]=a[i];
        a0[i]=a[i];
    }
    while(m--){
        int u,v;
        cin>>u>>v;
        a1[u]=max(a1[u],v);
        a0[u]=min(a0[u],v);
    }
    for(i=1;i<=n;i++){
        q[2*i-1]=node{2*i-1,a0[i],2,i};
        q[2*i]=node{2*i,a[i],1,i};
    }
    for(i=1;i<=2*n;i++)
        q0[i]=q[i];
    for(i=1;i<=n;i++)
        f[i]=1;
    solve(1,2*n);
    int ans=0;
    for(i=1;i<=n;i++){
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12744458.html