乱搞+虚假莫队?+树状数组——cf1288E

感觉自己的解法有点歪

/*
每次把一个数提到最前面,问整个过程结束后1..n每个数出现最靠前的位置和最靠后的位置
最靠前:如果一个数被提前过,那么必然是1
        如果从来没被提前过,就是其原来的位置
最靠后:维护数i每次被提前的时间序列time[i][]
    time[i][1]到time[i][2]之间出现不同元素的个数就是其在这一段时间内i最靠后的位置
    i出现的最靠后位置就是所有这种位置取max,再和初始值取max 
*/
#include
using namespace std;
#define N 600005

int n,m,a[N],Max[N],flag[N],Min[N];
vector<int>times[N];
int q,block; 
struct Query{
    int l,r,col;
}Q[N];
int cmp(Query a,Query b){
    if(a.l/block == b.l/block)return a.r<b.r;
    return a.l<b.l;
}

int cnt[N],tot;
void add(int x){
    cnt[a[x]]++;
    if(cnt[a[x]]==1)tot++;
} 
void del(int x){
    cnt[a[x]]--;
    if(!cnt[a[x]])tot--; 
}

int c[N],vis[N];
void update(int x){
    while(x<=n){
        c[x]++;
        x+=x&-x;
    }
} 
int query(int x){
    int res=0;
    while(x){
        res+=c[x];
        x-=x&-x;
    }
    return res;
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)Max[i]=Min[i]=i;
    for(int i=1;i<=m;i++){
        cin>>a[i];
        flag[a[i]]=1;
    }
    for(int i=1;i<=n;i++)if(flag[i])Min[i]=1;
    
    for(int i=1;i<=m;i++){//每个数前有多少比其大的 
        if(vis[a[i]])continue;
        vis[a[i]]=1;
        Max[a[i]]+=query(n)-query(a[i]);
        update(a[i]);    
    }
    for(int i=1;i<=n;i++)
        if(!vis[i]){
            Max[i]+=query(n)-query(i);
        }
    
    for(int i=1;i<=m;i++)times[a[i]].push_back(i);
    for(int i=1;i<=n;i++)times[i].push_back(m+1);
    for(int i=1;i<=n;i++){
        for(int j=0;j1;j++){
            int l=times[i][j]+1,r=times[i][j+1]-1;
            if(l<=r){
                ++q;Q[q].l=l;Q[q].r=r;Q[q].col=i;
            }
        }    
    }
    
    block=sqrt(m);
    sort(Q+1,Q+1+q,cmp);
    
    int L=1,R=0;
    for(int i=1;i<=q;i++){
        while(L>Q[i].l)add(--L);
        while(RR);
        while(L);
        while(R>Q[i].r)del(R--);
        Max[Q[i].col]=max(tot+1,Max[Q[i].col]);
    }
    
    for(int i=1;i<=n;i++)cout<" "<'\n';
}
 

 

你可能感兴趣的:(乱搞+虚假莫队?+树状数组——cf1288E)