传送门:洛谷
给定序列 ( a 1 , a 2 , ⋯ , a n ) = ( 1 , 2 , ⋯ , n ) \left(a_{1}, a_{2}, \cdots, a_{n}\right)=(1,2, \cdots, n) (a1,a2,⋯,an)=(1,2,⋯,n),即 a i = i a_{i}=i ai=i 。
小蓝将对这个序列进行 m m m 次操作,每次可能是将 a 1 , a 2 , ⋯ , a q i a_{1}, a_{2}, \cdots, a_{q_{i}} a1,a2,⋯,aqi 降序排列,或者将 a q i , a q i + 1 , ⋯ , a n a_{q_{i}}, a_{q_{i}+1}, \cdots, a_{n} aqi,aqi+1,⋯,an 升序排列。
输入:
3 3
0 3
1 2
0 2
输出:
3 1 2
我认为这道题是一道比较变态的题目
首先这道题有大概两种解法:
\quad\quad 一种解法是栈+思维,这种解法的思维难度较高,不是很好理解,也不太能在赛场上能想到,如果想把玩一下这种解法,那么网上有大量的题解,此处就不在介绍了
\quad\quad 我主要介绍另外一种解法.对于一段数列,我们发现这段数列中的所有数字要么处于下降数列中,要么处于上升区间中(这个很好理解).然后我们考虑维护每一个数字是处于下降数列中(用0表示),还是处于上升数列中(使用1表示).
\quad\quad 考虑使用 f e n j i e d i a n fenjiedian fenjiedian来记录上升数列开始的位置(因为显然是从下降序列过渡到上升序列中)
\quad\quad 初始化:刚开始显然所有数字都处于上升数列中,所以所有数字的状态都是1
\quad\quad 对于区间 [ 1 , q ] [1,q] [1,q]进行降序排序,那么此时假设我们的 q < f e n j i a n d i a n q
\quad\quad 对于区间 [ 1 , q ] [1,q] [1,q]进行升序排序,此时我们做法和上述大致类似.只要找到所有状态为0的数字中从小到大选 f e n j i e d i a n − q + 1 fenjiedian-q+1 fenjiedian−q+1个数字即可(原因和上述类似,因为改变的肯定是区间中最小的)然后将这些数字的状态从1改为0即可
\quad\quad 那么对于最终的答案来说,我们只要收集每一个数字的状态,对于状态为0的数字我们从大到小输出即可.对于状态为1的数字我们从小到大进行输出即可
下面是具体的代码部分(码量较大):
#include
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
struct Segment_tree{
int l,r;
int sum,lazy;//sum记录1的个数
}tree[maxn*4];
void pushup(int rt) {
tree[rt].sum=tree[ls].sum+tree[rs].sum;
}
void build(int l,int r,int rt) {//建树操作
tree[rt].l=l;tree[rt].r=r;tree[rt].lazy=-1;
if(l==r) {
tree[rt].sum=1;
return ;
}
int mid=(l+r)>>1;
build(lson);build(rson);
pushup(rt);
}
void pushdown(int rt) {
if(tree[rt].lazy==1) {
tree[ls].sum=tree[ls].r-tree[ls].l+1;tree[rs].sum=tree[rs].r-tree[rs].l+1;
}
else {
tree[ls].sum=tree[rs].sum=0;
}
tree[ls].lazy=tree[rt].lazy;tree[rs].lazy=tree[rt].lazy;
tree[rt].lazy=-1;
}
void update0(int l,int r,int rt,int cnt) {//区间置0
if(tree[rt].sum<=cnt) {
tree[rt].sum=0;
tree[rt].lazy=0;
return ;
}
if(tree[rt].lazy!=-1) pushdown(rt);
int mid=(tree[rt].l+tree[rt].r)>>1;
int lssum=tree[ls].sum;//注意这里
if(tree[ls].sum>=cnt) update0(l,mid,ls,cnt);
else update0(l,mid,ls,cnt),update0(mid+1,r,rs,cnt-lssum);
pushup(rt);
}
void update1(int l,int r,int rt,int cnt) {//区间置1
int lenrt=tree[rt].r-tree[rt].l+1;
if(lenrt-tree[rt].sum<=cnt) {
tree[rt].sum=tree[rt].r-tree[rt].l+1;
tree[rt].lazy=1;
return ;
}
if(tree[rt].lazy!=-1) pushdown(rt);
int mid=(tree[rt].l+tree[rt].r)>>1;
int lenls=tree[ls].r-tree[ls].l+1;
int lenrs=tree[rs].r-tree[rs].l+1;
int lssum=lenls-tree[ls].sum;//注意这里
if(lenls-tree[ls].sum>=cnt) update1(l,mid,ls,cnt);
else update1(l,mid,ls,cnt),update1(mid+1,r,rs,cnt-lssum);
pushup(rt);
}
int query(int pos,int rt) {//查询一个位置的数字状态
if(tree[rt].l==pos&&tree[rt].r==pos) {
return tree[rt].sum;
}
if(tree[rt].lazy!=-1) pushdown(rt);
int mid=(tree[rt].l+tree[rt].r)>>1;
if(pos<=mid) return query(pos,ls);
else return query(pos,rs);
}
int n,m;
int main() {
n=read();m=read();
int fenjiedian=1;//分界点
build(root);
for(int i=1;i<=m;i++) {
int opt=read();
if(opt==0) {
int p=read();
if(p<fenjiedian) continue;
update0(1,n,1,p-fenjiedian+1);
fenjiedian=p+1;
}
else {
int q=read();
if(q>=fenjiedian) continue;
update1(1,n,1,fenjiedian-q);
fenjiedian=q;
}
}
vector<int>ans0;vector<int>ans1;
for(int i=1;i<=n;i++) {
if(query(i,1)) {
ans1.push_back(i);
}
else {
ans0.push_back(i);
}
}
for(int i=ans0.size()-1;i>=0;i--) printf("%d ",ans0[i]);
for(int i=0;i<ans1.size();i++) printf("%d ",ans1[i]);
return 0;
}