题解 CF1288E 【Messenger Simulator】
题解 CF1288E 【Messenger Simulator】
简单思维+数据结构
1.首先发现x的最小值一定是x或1(x出现过就为1,否则为x)
2.然后我们发现x最大值要么是x,要么是出现x 之前的 x所在位置。这个我们直接用线段树维护每个值的位子即可。相当于对于一个数,他会把比他大的数都加1。修改某个数的位子,就先消除这个数之前的+1,然后把他放到最前,在把后面的数加1。
代码:
#include<bits/stdc++.h> using namespace std; #define next Next #define gc getchar //#define int long long const int N=1e6+5; int n,m,mi[N],ma[N],pos[N],tree[N*4],lazy[N*4]; //char buf[1<<21],*p1=buf,*p2=buf; //inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} inline int read() { int ret=0,f=0;char c=gc(); while(!isdigit(c)){if(c=='-')f=1;c=gc();} while(isdigit(c)){ret=ret*10+c-48;c=gc();} if(f)return -ret;return ret; } void pushdown(int nod) { tree[nod*2]+=lazy[nod]; tree[nod*2+1]+=lazy[nod]; lazy[nod*2]+=lazy[nod]; lazy[nod*2+1]+=lazy[nod]; lazy[nod]=0; } void change(int nod,int l,int r,int L,int R,int val) { if(l==L&&r==R) { tree[nod]+=val; lazy[nod]+=val; return; } pushdown(nod); int mid=(l+r)/2; if(R<=mid)change(nod*2,l,mid,L,R,val); else if(L>mid)change(nod*2+1,mid+1,r,L,R,val); else{ change(nod*2,l,mid,L,mid,val); change(nod*2+1,mid+1,r,mid+1,R,val); } tree[nod]=tree[nod*2]+tree[nod*2+1]; } int find(int nod,int l,int r,int x) { if(l==r)return tree[nod]; pushdown(nod); int mid=(l+r)/2; if(x<=mid)return find(nod*2,l,mid,x); else return find(nod*2+1,mid+1,r,x); } signed main() { n=read();m=read(); for(int i=1;i<=n;i++)mi[i]=ma[i]=i; for(int i=1;i<=n;i++)change(1,0,n+m,pos[i]=i+m,n+m,1); for(int i=1;i<=m;i++) { int x=read(); mi[x]=1; ma[x]=max(ma[x],find(1,0,n+m,pos[x])); change(1,0,n+m,pos[x],n+m,-1); pos[x]=m-i; change(1,0,n+m,pos[x],n+m,1); } for(int i=1;i<=n;i++)ma[i]=max(ma[i],find(1,0,n+m,pos[i])); for(int i=1;i<=n;i++)printf("%d %d\n",mi[i],ma[i]); return 0; } /* 发现如果一个数x没有出现,那么最小值一定是x 出现了,最小值就是1 最大值要么是x,要么是出现x前的值,这个我们线段树维护一下即可,区间加,单点查 */
xuxuxuxuxu 文章被收录于专栏
信息学竞赛