[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 }