[loj2706]文本编辑器

考虑维护所有活动操作所构成的单调栈(后缀级别最小值),对操作$a_{i}$分类讨论:

1.若$a_{i}>0$,显然即将单调栈清空并将$i$加入单调栈

2.若$a_{i}<0$,在单调栈中找到$i$撤销的操作$a_{j}$,则有以下结论——

结论:此时$j$之前的操作(不包括$j$)状态与$j-1$时相同

引理:若$j$在$i$时的单调栈中,则$i$时 $j$以及$j$之前的操作 状态与$j$时相同

将结论和引理一起归纳,显然成立

换言之,此时的单调栈是在$j-1$时的单调栈基础上加入$i$(需要弹出不比$a_{i}$级别小的操作)

进一步的,显然所有单调栈构成一棵树形结构,即$i$到根路径恰为$i$时的单调栈(从栈顶到栈底)

同时,树上只会新增叶子,那么用倍增去维护即可

时间复杂度为$o(n\log n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 300005
 4 int n,a[N],fa[N][20];
 5 int find(int k,int d){
 6     if (a[k]>d)return k;
 7     for(int i=19;i>=0;i--)
 8         if (a[fa[k][i]]<=d)k=fa[k][i];
 9     return fa[k][0];
10 }
11 int main(){
12     scanf("%d",&n);
13     for(int i=1;i<=n;i++){
14         scanf("%d",&a[i]);
15         if (a[i]>0)fa[i][0]=i;
16         else fa[i][0]=find(find(i-1,a[i])-1,a[i]);
17         for(int j=1;j<20;j++)fa[i][j]=fa[fa[i][j-1]][j-1];
18         printf("%d\n",a[find(i,0)]);
19     }
20     return 0;
21 } 
View Code

 

posted @ 2022-01-04 08:47  PYWBKTDA  阅读(47)  评论(0编辑  收藏  举报