操做數,通常用來作那些對數列進行添加、撤銷操做的題。node
假設一開始有一個空數列,有三個操做ios
(1)在數列後加一個數ide
(2)求數列中某位置的值測試
(3)撤銷掉最後進行的若干次操做(1和3)spa
考慮建一棵樹,1操做則爲在當前節點下新加一個節點,2操做求數列k位置值,則爲從根節點到當前節點k個節點的位置的節點code
3操做撤銷掉最後進行的k次操做則爲回溯k個節點,同時記錄回溯前的當前節點和回溯後的當前節點。blog
因此每次進行查詢的時候,先從當前節點找父親,一直找到根節點,記錄節點個數,而後節點個數-k獲得當前節點到要查詢的節點的距離。內存
撤銷操做的時候,父親是1操做的節點就往上找父親,父親是3操做節點就跳到那個3操做回溯以前的那個「當前節點」ci
例如這道題:io
給一個空數列,有M次操做,每次操做是如下三種之一:
(1)在數列後加一個數
(2)求數列中某位置的值
(3)撤銷掉最後進行的若干次操做(1和3)
9 A 1 A 2 A 3 Q 3 U 1 A 4 Q 3 U 2 Q 3
3 4 3
#include <cstdio> #include <iostream> const int MaxN = 100001; int fa[MaxN]; //bool edge[MaxN][MaxN]; int n; int V[MaxN]; int back[MaxN]; int main() { scanf("%d",&n); int now_node; char XX; std::cin>>XX; int xx; scanf("%d",&xx); now_node = 1; int node_cnt = 1; V[node_cnt] = xx; for(int l = 2; l <= n; l++){ char X; std::cin>>X; if(X == 'A'){ int nx; scanf("%d",&nx); V[++node_cnt] = nx; fa[node_cnt] = now_node; //edge[now_node][node_cnt] = 1; now_node = node_cnt; } else if(X == 'U'){ int nx; scanf("%d",&nx); int last_node = now_node; for(int i = 1; i <= nx; i++){ if(!back[now_node]) now_node = fa[now_node]; else now_node = back[now_node]; } back[now_node] = last_node; } else if(X == 'Q'){ int nx; scanf("%d",&nx); int count = 0; int tmp = now_node; while(1){ if(!fa[tmp]){ break; } tmp = fa[tmp]; count++; } count = count - nx; tmp = now_node; for(int i = 1; i <= count; i++){ tmp = fa[tmp]; } printf("%d\n",V[tmp]); } } return 0; }