Educational Codeforces Round 80 (Rated for Div. 2) E

题意

初始为 1 n 1-n m m 次操作把一个数提到最前面,最后输出每个数的最前位置和最后位置。

题解

最前位置就是初始位置或者 1 1
最后位置怎么得到呢?
我们可以发现就是算上从开始到第一次被提,和最后一次被提到结束,两次被提之间。求这之间的的不同种类数,但是第一个还要求大于自己的不同种类数。
不过我们可以简单的减小一下处理难度,在初始倒入插入一下,这样子就能保证比自己小的没有影响了。
5 4 3 2 1 3 5 1 4 5\quad 4\quad 3\quad 2\quad 1\quad 3 \quad5\quad 1\quad 4
这个时候莫队就可以解决了, ( n + m ) n + m (n +m)\sqrt{n+m} 的复杂度。

或者采用第二种方法,模拟
在前面加 m m 0 0
0 0 0 0 1 2 3 4 5 0\quad 0\quad 0\quad 0\quad 1\quad 2 \quad3\quad 4\quad 5
如果提一个 3 3 到前面,可以这样做:
0 0 0 3 1 2 0 4 5 0\quad 0\quad 0\quad 3\quad 1\quad 2 \quad0\quad 4\quad 5

这样就可以处理了,用树状数组求出在自己前面的数量,并且保存一下自己的当前位置。
根据上面的思考,每次只需要在提到前面前计算一下即可,以及最后结束的时候。

#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define RFOR(i,a,b) for(int i=a;i>=b;i--)
#define sf(x) scanf("%d",&x)
#define inf 0x3f3f3f3f
using namespace std;
 
typedef long long ll;
const int maxn = 600000+500;
const ll mod = 1e9+7;
 
int n,m;
int A[maxn],num[maxn],pos[maxn];
int Mi[maxn],Mx[maxn];
vector<int>G[maxn];
int L=1,R=1,block,ret;
 
inline void add(int x){
    num[x]++;
    if(num[x]==1)ret++;
}
 
inline void del(int x){
    num[x]--;
    if(num[x]==0)ret--;
}
 
struct node{
    int l,r,index;
    friend bool operator < (node a,node b){
        if(pos[a.l]!=pos[b.l])return a.l<b.l;
        else{
            if(pos[a.l]&1)return a.r<b.r;
            else return a.r>b.r;
        }
    }
}Q[1000050];
 
int main(){
    cin>>n>>m;
    FOR(i,1,n)A[i]=n-i+1,Mi[i]=Mx[i]=i;
    FOR(i,1,m)sf(A[n+i]),Mi[A[n+i]]=1;
    block=sqrt(n+m);
    FOR(i,1,n+m)pos[i]=(i-1)/block+1;
    FOR(i,1,n+m)G[A[i]].push_back(i);
    int num=0;
    FOR(i,1,n){
        for(int j=1;j<G[i].size();j++){
            ++num;Q[num].l=G[i][j-1]+1,Q[num].r=G[i][j]-1;
            Q[num].index=i;
            if(Q[num].l>Q[num].r)--num;
        }
        ++num;Q[num].l=G[i][G[i].size()-1]+1,Q[num].r=n+m;
        Q[num].index=i;
        if(Q[num].l>Q[num].r)--num;
    }
    //FOR(i,1,num)cout<<Q[i].l<<" "<<Q[i].r<<endl;
    sort(Q+1,Q+1+num);
    add(A[1]);
    FOR(i,1,num){
        while(L>Q[i].l){L--;add(A[L]);}
        while(L<Q[i].l){del(A[L]);L++;}
        while(R<Q[i].r){R++;add(A[R]);}
        while(R>Q[i].r){del(A[R]);R--;}
        Mx[Q[i].index]=max(Mx[Q[i].index],ret+1);
    }
    FOR(i,1,n)printf("%d %d\n",Mi[i],Mx[i]);
}
#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define RFOR(i,a,b) for(int i=a;i>=b;i--)
#define sf(x) scanf("%d",&x)
#define inf 0x3f3f3f3f
using namespace std;

typedef long long ll;
const int maxn = 600000+500;
const ll mod = 1e9+7;

int n,m;
int A[maxn],C[maxn];
int Mi[maxn],Mx[maxn],pos[maxn];

int lowbit(int x){return (x&(-x));}

void change(int x,int d){
    for(int i=x;i<=maxn;i+=lowbit(i))C[i]+=d;
}

int query(int x){
    if(x==0)return 0;
    int ret=0;
    for(int i=x;i;i-=lowbit(i))ret+=C[i];
    return ret;
}

int main(){
    cin>>n>>m;
    FOR(i,1,n)pos[i]=m+i,Mi[i]=i,Mx[i]=i;
    FOR(i,1,m)sf(A[i]);
    FOR(i,1,n)change(pos[i],1);
    //FOR(i,1,n)cout<<query(m+i)<<endl;
    FOR(i,1,m){
        int tmp=query(pos[A[i]]);
        //cout<<pos[A[i]]-1<<" "<<tmp<<endl;;
        Mx[A[i]]=max(Mx[A[i]],tmp);
        Mi[A[i]]=min(Mi[A[i]],1);
        change(pos[A[i]],-1);
        pos[A[i]]=m-i+1;
        change(pos[A[i]],1);
    }
    FOR(i,1,n){
        int tmp=query(pos[i]);
        Mx[i]=max(Mx[i],tmp);
    }
    FOR(i,1,n)printf("%d %d\n",Mi[i],Mx[i]);
}
发布了203 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/mxYlulu/article/details/104082579