树状数组
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x))
#define int long long
const int N = 1e6+5;
int a[N],n,q,opt,i,x,tree[2*N];
inline void update(int x,int d){
while(x <= n) {
tree[x] += d;
x += lowbit(x);
}
}
inline int sum(int x) {
int ans = 0;
while(x > 0) {
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n>>q;
for(int i = 1;i<=n;i++) cin>>a[i];
for(int i = 1;i<=n;i++) update(i,a[i]);
while(q--) {
cin>>opt>>i>>x;
if(opt == 1){
update(i,x);
}
else{
cout<<sum(x) - sum(i-1)<<'\n';
}
}
return 0;
}
线段树
#include<bits/stdc++.h>
using namespace std;
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 1e6,inf = 1e9;
int a[N];
namespace sgt{
#define ls (p << 1)
#define rs (ls | 1)
#define mid ((pl + pr) >> 1)
int sum[N],mx[N],mn[N],tag[N];
void push_up(int p) {
sum[p] = sum[ls] + sum[rs];
mx[p] = max(mx[ls],mx[rs]);
mn[p] = min(mn[ls],mn[rs]);
}
void addtag(int p,int pl,int pr,int d) {
sum[p] += (pr - pl + 1) * d;
mx[p] += d;
mn[p] += d;
tag[p] += d;
}
void push_down(int p,int pl,int pr) {
if(tag[p]) {
addtag(ls,pl,mid,tag[p]);
addtag(rs,mid+1,pr,tag[p]);
tag[p] = 0;
}
}
void build(int p,int pl,int pr) {
if(pl == pr) {
mx[p] = mn[p] =sum[p] = a[pl];
return;
}
build(ls,pl,mid);
build(rs,mid+1,pr);
push_up(p);
}
void update(int p,int pl,int pr,int l,int r,int d) {
if(l <= pl && pr <= r) {
addtag(ls,pl,mid,d);
return;
}
push_down(p,pl,pr);
if(l <= mid) update(ls,pl,mid,l,r,d);
if(r > mid) update(rs,mid+1,pr,l,r,d);
push_up(p);
}
int query_min(int p,int pl,int pr,int l,int r) {
if(l <= pl && pr <= r) return mn[p];
int res = inf;
push_down(p,pl,pr);
if(l <= mid) res = min(res,query_min(ls,pl,mid,l,r));
if(r > mid) res = min(res,query_min(rs,mid+1,pr,l,r));
return mn[p];
}
int query_max(int p,int pl,int pr,int l,int r) {
if(l <= pl && pr <= r) return mx[p];
int res = 0;
push_down(p,pl,pr);
if(l <= mid) res = max(res,query_max(ls,pl,mid,l,r));
if(r > mid) res = max(res,query_max(rs,mid+1,pr,l,r));
return res;
}
int query_sum(int p,int pl,int pr,int l,int r) {
if(l <= pl && pr <= r) return sum[p];
int res = 0;
push_down(p,pl,pr);
if(l <= mid) res += query_max(ls,pl,mid,l,r);
if(r > mid) res += query_max(rs,mid+1,pr,l,r);
return res;
}
}
signed main() {
return 0;
}
树链剖分
#include <bits/stdc++.h>
using namespace std;
#define Dec(i,a,n) for(register int i = a;i>=n;i--)
#define LOG2(x) __lg(x)
const int N = 1e5+10;
int n,m,r,mod;
struct Edge{
int to,nxt;
}edge[N<<1];
int head[N<<1],cnt;
void init() {
For(i,0,(N<<1)-1) edge[i].nxt = -1,head[i] = -1;
cnt = 0;
}
void addedge(int u,int v) {
edge[cnt].to = v;
edge[cnt].nxt = head[u];
head[u] = cnt++;
}
int w[N],w_new[N];
namespace sgm{
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((pl + pr) >> 1)
#define int long long
int seg[N<<2],tag[N<<2];
void push_up(int p) {
seg[p] = seg[ls] + seg[rs];
}
void addtag(int p,int pl,int pr,int d) {
tag[p] += d;
seg[p] = (seg[p]+d*(pr - pl + 1))%mod;
}
void push_down(int p,int pl,int pr) {
if(tag[p]) {
addtag(ls,pl,mid,tag[p]);
addtag(rs,mid+1,pr,tag[p]);
tag[p] = 0;
}
}
void build(int p,int pl,int pr) {
tag[p] = 0;
if(pl == pr) {
seg[p] = w_new[pl];
return;
}
build(ls,pl,mid);
build(rs,mid+1,pr);
push_up(p);
}
void update(int p,int pl,int pr,int l,int r,int d) {
if(l <= pl &&pr <= r) {
addtag(p,pl,pr,d);
return;
}
push_down(p,pl,pr);
if(l <= mid) update(ls,pl,mid,l,r,d);
if(r > mid) update(rs,mid+1,pr,l,r,d);
push_up(p);
}
int query(int p,int pl,int pr,int l,int r) {
if(l <= pl && pr <= r) return seg[p] %= mod;
push_down(p,pl,pr);
int res = 0;
if(l <= mid) res += query(ls,pl,mid,l,r);
if(r > mid) res += query(rs,mid+1,pr,l,r);
return res;
}
}
int son[N],id[N],fa[N],dep[N],siz[N],top[N];
void dfs1(int x,int f) {
dep[x] = dep[f] + 1;
fa[x] = f;
siz[x] = 1;
for(int i = head[x];~i;i = edge[i].nxt) {
int y = edge[i].to;
if(y^f) {
fa[y] = x;
dfs1(y,x);
siz[x] += siz[y];
if(!son[x]||siz[son[x]] < siz[y]) son[x] = y;
}
}
}
int num = 0;
void dfs2(int x,int topx) {
id[x] = ++num;
w_new[num] = w[x];
top[x] = topx;
if(!son[x]) return;
dfs2(son[x],topx);
for(int i = head[x];~i;i = edge[i].nxt) {
int y = edge[i].to;
if(y != fa[x] &&y != son[x]) dfs2(y,y);
}
}
void update_r(int x,int y,int z) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x,y);
sgm::update(1,1,n,id[top[x]],id[x],z);
x = fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
sgm::update(1,1,n,id[x],id[y],z);
}
int query_r(int x,int y) {
int ans =0 ;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x,y);
ans += sgm::query(1,1,n,id[top[x]],id[x]);
ans %= mod;
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
ans += sgm::query(1,1,n,id[x],id[y]);
return ans % mod;
}
void update_s(int x,int k) {
sgm::update(1,1,n,id[x],id[x] + siz[x]-1,k);
}
int query_s(int x) {
return sgm::query(1,1,n,id[x],id[x] + siz[x] -1)%mod;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
init();
cin>>n>>m>>r>>mod;
for(int i = 1;i<=n;i++) cin>>w[i];
For(i,1,n-1) {
int u,v;
cin>>u>>v;
addedge(u,v);
addedge(v,u);
}
dfs1(r,0);
dfs2(r,r);
sgm::build(1,1,n);
while(m--) {
int k,x,y,z;
cin>>k;
switch(k) {
case 1:
cin>>x>>y>>z;
update_r(x,y,z);
break;
case 2:
cin>>x>>y;
cout<<query_r(x,y)<<'\n';
break;
case 3:
cin>>x>>y;
update_s(x,y);
break;
case 4:
cin>>x;
cout<<query_s(x)<<'\n';
break;
}
}
return 0;
}
可持久化线段树
#include <bits/stdc++.h>
using namespace std;
#define mid ((pl + pr) >> 1)
#define int long long
const int N = 2e5+ 10;
struct node{
int l,r,sum;
}seg[N<<5];
int cnt = 0;
int a[N],b[N],root[N];
int build(int pl,int pr) {
int rt = ++ cnt;
seg[rt].sum = 0;
if(pl < pr) {
seg[rt].l = build(pl,mid);
seg[rt].r = build(mid+1,pr);
}
return rt;
}
int update(int pre,int pl,int pr,int x) {
int rt = ++cnt;
seg[rt].l = seg[pre].l;
seg[rt].r = seg[pre].r;
seg[rt].sum = seg[pre].sum + 1;
if(pl < pr) {
if(x <= mid) seg[rt].l = update(seg[pre].l,pl,mid,x);
else seg[rt].r = update(seg[pre].r,mid+1,pr,x);
}
return rt;
}
int query(int u,int v,int pl,int pr,int k) {
if(pl == pr) return pl;
int x = seg[seg[v].l].sum - seg[seg[u].l].sum;
if(x >= k) return query(seg[u].l,seg[v].l,pl,mid,k);
else return query(seg[u].r,seg[v].r,mid+1,pr,k-x);
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int n,m;
cin>>n>>m;
for(int i = 1;i<=n;i++) {
cin>>a[i];
b[i] = a[i];
}
sort(b + 1,b + n + 1);
int size = unique(b + 1,b + n + 1) - b-1;
for(int i = 1;i<=n;i++) {
int x = lower_bound(b + 1,b + 1 + size,a[i]) - b;
root[i] = update(root[i-1],1,size,x);
}
while(m--) {
int x,y,k;
cin>>x>>y>>k;
int t = query(root[x-1],root[y],1,size,k);
cout<<b[t]<<'\n';
}
return 0;
}
区间历史最大值线段树
AC-code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 1e5+5,inf = 0x3f3f3f3f3f3f3f3fLL;
int T,E,a[N];
int ans[N<<2],history_ans[N<<2];
void getmax(int &a,int b) {if(b > a) a = b;}
namespace sgt{
#define ls (p << 1)
#define rs (ls | 1)
#define mid ((pl + pr) >> 1)
int sum[N<<2],val[N<<2];
bool vis[N<<2];
int max_sum[N<<2],max_val[N<<2];
void push_up(int p) {
ans[p] = max(ans[ls],ans[rs]);
history_ans[p] = max(history_ans[ls],history_ans[rs]);
}
void push_sum(int p,int k,int maxk) {
if(vis[p]) {
getmax(max_val[p],val[p] + maxk);
getmax(history_ans[p],ans[p] + maxk);\
val[p] += k;
}else {
getmax(max_sum[p],sum[p] + maxk);
getmax(history_ans[p],ans[p] + maxk);
sum[p] += k;
}
ans[p] += k;
}
void push_val(int p,int k,int maxk) {
if(vis[p]) {
getmax(max_val[p],maxk);
getmax(history_ans[p],maxk);
}else {
vis[p] = true;
max_val[p] = maxk;
getmax(history_ans[p],maxk);
}
ans[p] = val[p] = k;
}
void push_down(int p){
push_sum(ls,sum[p],max_sum[p]);
push_sum(rs,sum[p],max_sum[p]);
sum[p] = max_sum[p] = 0;
if(vis[p]) {
push_val(ls,val[p],max_val[p]);
push_val(rs,val[p],max_val[p]);
vis[p] = 0;
val[p] = max_val[p] = 0;
}
}
void build(int p,int pl,int pr) {
if(pl == pr) {
history_ans[p] = ans[p] = a[pl];
return;
}
build(ls,pl,mid);
build(rs,mid+1,pr);
push_up(p);
}
int query(int p,int pl,int pr,int l,int r) {
if(l <= pl && pr <= r) return ans[p];
push_down(p);
int res = -inf;
if(l <= mid) res = max(res,query(ls,pl,mid,l,r));
if(r > mid) res = max(res,query(rs,mid+1,pr,l,r));
return res;
}
int queryHistoryAns(int p,int pl,int pr,int l,int r) {
if(l <= pl && pr <= r) return history_ans[p];
push_down(p);
int res = -inf;
if(l <= mid) getmax(res,queryHistoryAns(ls,pl,mid,l,r));
if(r > mid) getmax(res,queryHistoryAns(rs,mid+1,pr,l,r));
return res;
}
void add(int p,int pl,int pr,int l,int r,int k) {
if(l <= pl && pr <= r) {
push_sum(p,k,k);
return;
}
push_down(p);
if(l <= mid) add(ls,pl,mid,l,r,k);
if(r > mid) add(rs,mid+1,pr,l,r,k);
push_up(p);
}
void assign(int p,int pl,int pr,int l,int r,int k) {
if(l <= pl && pr <= r) {
push_val(p,k,k);
return;
}
push_down(p);
if(l <= mid) assign(ls,pl,mid,l,r,k);
if(r > mid) assign(rs,mid+1,pr,l,r,k);
push_up(p);
}
}
void nowMax() {
int x = rd(),y = rd();
wt(sgt::query(1,1,T,x,y));
putchar('\n');
}
void historyAns() {
int x = rd(),y = rd();
wt(sgt::queryHistoryAns(1,1,T,x,y));
putchar('\n');
}
void getadd() {
int x = rd(),y = rd(),z = rd();
sgt::add(1,1,T,x,y,z);
}
void getcov() {
int x = rd(),y = rd(),z = rd();
sgt::assign(1,1,T,x,y,z);
}
signed main() {
T = rd();
for(int i = 1;i<=T;i++)
a[i] = rd();
sgt::build(1,1,T);
E = rd();
while(E--) {
char opt = getchar();
while(opt == ' ' ||opt == '\n') opt = getchar();
switch(opt) {
case 'Q':
nowMax();
break;
case 'A':
historyAns();
break;
case 'P':
getadd();
break;
case 'C':
getcov();
break;
default:
break;
}
}
return 0;
}
历史版本和线段树[Segment Beats!]
AC-code:
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
int n,q;
const int N = 3e5+5;
#define ls (p << 1)
#define rs (ls | 1)
#define mid ((pl + pr) >> 1)
struct node{
ull taga,tagb,s,sa,sb,h,ha,hb,upd,ans,len;
}t[N<<2];
ull a[N],b[N],ans[N];
void push_up(int p) {
t[p].s = t[ls].s + t[rs].s;
t[p].sa = t[ls].sa + t[rs].sa;
t[p].sb = t[ls].sb + t[rs].sb;
t[p].ans = t[ls].ans + t[rs].ans;
}
void addtag(int p,node d) {
t[p].ans += t[p].s * d.upd + t[p].sa * d.hb + t[p].sb * d.ha + d.h * t[p].len;
t[p].h += t[p].taga * t[p].tagb * d.upd + t[p].taga * d.hb + t[p].tagb * d.ha + d.h;
t[p].ha += t[p].taga * d.upd + d.ha;
t[p].hb += t[p].tagb * d.upd + d.hb;
t[p].s += t[p].sa * d.tagb + t[p].sb * d.taga + d.taga * d.tagb * t[p].len;
t[p].sa += d.taga * t[p].len;
t[p].sb += d.tagb * t[p].len;
t[p].upd += d.upd;
t[p].taga += d.taga;
t[p].tagb += d.tagb;
}
void push_down(int p) {
addtag(ls,t[p]);
addtag(rs,t[p]);
t[p].h = t[p].ha = t[p].hb = t[p].upd = t[p].taga = t[p].tagb = 0;
}
void build(int p,int pl,int pr) {
t[p].len = (pr - pl + 1);
if(pl == pr) return;
build(ls,pl,mid);
build(rs,mid+1,pr);
}
void update(int p,int pl,int pr,int l,int r,ull x,int opt) {
if(l <= pl && pr <= r){
if(opt) addtag(p,(node){0,x,0,0,0,0,0,0,0,0,pr - pl + 1});
else addtag(p,(node){x,0,0,0,0,0,0,0,0,0,pr - pl + 1});
return;
}
push_down(p);
if(l <= mid) update(ls,pl,mid,l,r,x,opt);
if(r > mid) update(rs,mid+1,pr,l,r,x,opt);
push_up(p);
}
ull query(int p,int pl,int pr,int l,int r) {
if(l <= pl && pr <= r) return t[p].ans;
ull re = 0;
push_down(p);
if(l <= mid) re += query(ls,pl,mid,l,r);
if(r > mid) re += query(rs,mid+1,pr,l,r);
return re;
}
vector<array<int,2>> Q[N];
int sta[N],topa,stb[N],topb;
signed main() {
int T;
scanf("%d %d",&T,&n);
for(int i = 1;i<=n;i++) scanf("%llu",&a[i]);
for(int i = 1;i<=n;i++) scanf("%llu",&b[i]);
scanf("%d",&q);
for(int i = 1;i<=q;i++) {
int l,r;
scanf("%d %d",&l,&r);
Q[r].emplace_back(array<int,2>{l,i});
}
build(1,1,n);
topa = topb = 1;
b[0] = a[0] = n + 1;
for(int i = 1;i<=n;i++) {
while(a[sta[topa]] < a[i]) {
update(1,1,n,sta[topa - 1] + 1,sta[topa],-a[sta[topa]],0);
topa--;
}
update(1,1,n,sta[topa] + 1,i,a[i],0);
sta[++topa] = i;
while(b[stb[topb]] < b[i]) {
update(1,1,n,stb[topb - 1] + 1,stb[topb],-b[stb[topb]],1);
topb--;
}
update(1,1,n,stb[topb] + 1,i,b[i],1);
stb[++topb] = i;
addtag(1,(node){0,0,0,0,0,0,0,0,1,0,0});
for(auto k : Q[i]) ans[k[1]] = query(1,1,n,k[0],i);
}
for(int i = 1;i<=q;i++) printf("%llu\n",ans[i]);
return 0;
}
[Vani有约会] 雨天的尾巴 /【模板】线段树合并
线段树合并:即将大量权值线段树合并到一颗线段树上
本题作为板子却出的非常巧妙,让树上差分和线段树合并巧妙结合起来
因为在线段树合并的过程就是 自下而上 的,这个是结合树上差分的重要条件
对于题目中的路径修改,只需要在 x 、 y x、y x、y 处 的线段树 z z z 位置 + 1 +1 +1,在 l c a ( x , y ) lca(x,y) lca(x,y) 和 f a l c a ( x , y ) fa_{lca(x,y)} falca(x,y) 处的线段树 z z z 位置 − 1 -1 −1 即可
树剖求 L C A LCA LCA:
int n,m,head[N],nxt[N<<1],to[N<<1],cnt;
void init(){memset(head,-1,sizeof(head));}
void add(int u,int v){
nxt[cnt] = head[u];
to[cnt] = v;
head[u] = cnt++;
}
int dep[N],fa[N],son[N],top[N],siz[N];
void dfs1(int x,int f) {
siz[x] = 1;
fa[x] = f;
dep[x] = dep[f] + 1;
for(int i = head[x];~i;i = nxt[i]) {
int y = to[i];
if(y ^ f) {
dfs1(y,x);
siz[x] += siz[y];
if(siz[son[x]] < siz[y]) son[x] = y;
}
}
}
void dfs2(int x,int topx) {
top[x] = topx;
if(!son[x]) return;
dfs2(son[x],topx);
for(int i = head[x];~i;i = nxt[i]) {
int y = to[i];
if(y ^ fa[x] && y ^ son[x]) dfs2(y,y);
}
}
int LCA(int x,int y) {
while(top[x] ^ top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x,y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
动态开点线段树:
int root[N],tot;
int ls[N * 50],rs[N * 50],sum[N*50],typ[N*50],ans[N];
#define mid ((pl + pr) >> 1)
void push_up(int p) {
if(sum[ls[p]] >= sum[rs[p]]) {
sum[p] = sum[ls[p]];
typ[p] = typ[ls[p]];
}else {
sum[p] = sum[rs[p]];
typ[p] = typ[rs[p]];
}
}
void update(int &p,int pl,int pr,int k,int d) {
if(!p) p = ++tot;
if(pl == pr){sum[p] += d;typ[p] = k;return;}
if(k <= mid) update(ls[p],pl,mid,k,d);
else update(rs[p],mid+1,pr,k,d);
push_up(p);
}
接下来是合并环节:
首先,如果一个位置只在两颗线段树之一中存在,那么直接接在合并的线段树上
if(!x || !y) return x + y;
如果,访问到同一个叶子节点,参数合并
if(pl == pr) {sum[x] += sum[y];return x;}
在遍历过程中,更新节点 p p p 的 l s ls ls 和 r s rs rs
ls[x] = merge(ls[x],ls[y],pl,mid);
rs[x] = merge(rs[x],rs[y],mid+1,pr);
将新的节点 x x x 进行整合 l s 、 r s ls、rs ls、rs 的答案
push_up(x);
最后,将 x x x 节点返回,作为父亲节点的左或右孩子
return x;
所以,合并函数为:
int merge(int x,int y,int pl,int pr) {
if(!x || !y) return x + y;
if(pl == pr) {sum[x] += sum[y];return x;}
ls[x] = merge(ls[x],ls[y],pl,mid);
rs[x] = merge(rs[x],rs[y],mid+1,pr);
push_up(x);
return x;
}
递归合并的过程没什么好说的,遍历就可以了
void dfs3(int x,int f) {
for(int i = head[x];~i;i = nxt[i]) {
int y = to[i];
if(y ^ f) {
dfs3(y,x);
root[x] = merge(root[x],root[y],1,N);
}
}
ans[x] = sum[root[x]] ? typ[root[x]] : 0;
}
AC-code:
#include<bits/stdc++.h>
using namespace std;
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 1e5+5;
int n,m,head[N],nxt[N<<1],to[N<<1],cnt;
void init(){memset(head,-1,sizeof(head));}
void add(int u,int v){
nxt[cnt] = head[u];
to[cnt] = v;
head[u] = cnt++;
}
int dep[N],fa[N],son[N],top[N],siz[N];
void dfs1(int x,int f) {
siz[x] = 1;
fa[x] = f;
dep[x] = dep[f] + 1;
for(int i = head[x];~i;i = nxt[i]) {
int y = to[i];
if(y ^ f) {
dfs1(y,x);
siz[x] += siz[y];
if(siz[son[x]] < siz[y]) son[x] = y;
}
}
}
void dfs2(int x,int topx) {
top[x] = topx;
if(!son[x]) return;
dfs2(son[x],topx);
for(int i = head[x];~i;i = nxt[i]) {
int y = to[i];
if(y ^ fa[x] && y ^ son[x]) dfs2(y,y);
}
}
int LCA(int x,int y) {
while(top[x] ^ top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x,y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
int root[N],tot;
int ls[N * 50],rs[N * 50],sum[N*50],typ[N*50],ans[N];
#define mid ((pl + pr) >> 1)
void push_up(int p) {
if(sum[ls[p]] >= sum[rs[p]]) {
sum[p] = sum[ls[p]];
typ[p] = typ[ls[p]];
}else {
sum[p] = sum[rs[p]];
typ[p] = typ[rs[p]];
}
}
void update(int &p,int pl,int pr,int k,int d) {
if(!p) p = ++tot;
if(pl == pr){sum[p] += d;typ[p] = k;return;}
if(k <= mid) update(ls[p],pl,mid,k,d);
else update(rs[p],mid+1,pr,k,d);
push_up(p);
}
int merge(int x,int y,int pl,int pr) {
if(!x || !y) return x + y;
if(pl == pr) {sum[x] += sum[y];return x;}
ls[x] = merge(ls[x],ls[y],pl,mid);
rs[x] = merge(rs[x],rs[y],mid+1,pr);
push_up(x);
return x;
}
void dfs3(int x,int f) {
for(int i = head[x];~i;i = nxt[i]) {
int y = to[i];
if(y ^ f) {
dfs3(y,x);
root[x] = merge(root[x],root[y],1,N);
}
}
ans[x] = sum[root[x]] ? typ[root[x]] : 0;
}
signed main(){
init();
n = rd(),m = rd();
for(int i = 1,u,v;i<n;i++) {
add(u = rd(),v = rd());
add(v,u);
}
dfs1(1,0);
dfs2(1,1);
while(m--){
int a = rd(),b = rd(),z = rd();
update(root[a],1,N,z,1);
update(root[b],1,N,z,1);
int t = LCA(a,b);
update(root[t],1,N,z,-1);
update(root[fa[t]],1,N,z,-1);
}
dfs3(1,0);
for(int i = 1;i<=n;i++) {wt(ans[i]);putchar('\n');}
return 0;
}
【模板】线段树分裂
AC-code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 2e5+5;
typedef long long ll;
int n,m,root[N];
int ls[N * 22],rs[N*22],tot;
ll sum[N*22];
#define mid ((pl + pr) >> 1)
void merge(int &x,int y) {
if(!x || !y) {x += y;return;}
sum[x] += sum[y];
merge(ls[x],ls[y]);
merge(rs[x],rs[y]);
}
void split(int x,int &y,ll k) {
if(sum[x] == k) return;
y = ++tot;
sum[y] = sum[x] - k,sum[x] = k;
if(k <= sum[ls[x]]) split(ls[x],ls[y],k),swap(rs[x],rs[y]);
else split(rs[x],rs[y],k - sum[ls[x]]);
}
void update(int &p,int pl,int pr,int d,int k){
if(!p) p = ++tot;
sum[p] += k;
if(pl == pr) return;
if(d <= mid) update(ls[p],pl,mid,d,k);
else update(rs[p],mid+1,pr,d,k);
}
ll query(int p,int pl,int pr,int l,int r) {
if(pl > r|| pr < l) return 0;
if(l <= pl && pr <= r) return sum[p];
return query(ls[p],pl,mid,l,r) + query(rs[p],mid+1,pr,l,r);
}
int kth(int p,int pl,int pr,int k){
if(pl == pr) return pl;
if(k <= sum[ls[p]]) return kth(ls[p],pl,mid,k);
else return kth(rs[p],mid+1,pr,k - sum[ls[p]]);
}
int cnt = 1;
void Cut() {
int p = rd(),x = rd(),y = rd();
ll k1 = query(root[p],1,n,1,y),k2 = query(root[p],1,n,x,y);
int t = 0;
split(root[p],root[++cnt],k1 - k2);
split(root[cnt],t,k2);
merge(root[p],t);
}
void Move() {
int x = rd(),y = rd();
merge(root[x],root[y]);
}
void Add(){
int p = rd(),x = rd(),y = rd();
update(root[p],1,n,y,x);
}
void Find(){
int p = rd(),x = rd(),y = rd();
wt(query(root[p],1,n,x,y));
putchar('\n');
}
void findKth() {
int p = rd(),x = rd();
if(sum[root[p]] < x) putchar('-'),putchar('1');
else wt(kth(root[p],1,n,x));
putchar('\n');
}
signed main() {
n = rd(),m = rd();
int opt;
for(int i = 1;i<=n;i++) update(root[1],1,n,i,rd());
while(m--) {
opt = rd();
switch(opt){
case 0:
Cut();
break;
case 1:
Move();
break;
case 2:
Add();
break;
case 3:
Find();
break;
default:
findKth();
break;
}
}
return 0;
}
【模板】普通平衡树
FHQ-Treap:
#include <bits/stdc++.h>
using namespace std;
// 省略了头...
namespace my{
using namespace AllRangeApply_Define;
using namespace Atomic::normalSTD;
//using namespace Atomic::fastSTD;
//using namespace Atomic::SuperSTD;
const int M = 1e6+5;
int cnt = 0,root = 0;
struct node{
int ls,rs;
int key,pri;
int size;
}t[M];
#define ls(p) t[p].ls
#define rs(p) t[p].rs
#define pri(p) t[p].pri
void newnode(int x) {
cnt++;
t[cnt].size = 1;
t[cnt].ls = t[cnt].rs = 0;
t[cnt].key = x;
t[cnt].pri = rand();
}
void update(int u) {
t[u].size = t[ls(u)].size + t[rs(u)].size + 1;
}
void split(int u,int x,int &L,int &R) {
if(u == 0) {L = R = 0;return;}
if(t[u].key <= x) {
L = u;
split(rs(u),x,rs(u),R);
}else {
R = u;
split(ls(u),x,L,ls(u));
}
update(u);
}
int merge(int L,int R) {
if(L == 0 || R == 0 ) return L + R;
if(pri(L) > pri(R)) {
rs(L) = merge(rs(L),R);
update(L);
return L;
}else {
ls(R) = merge(L,ls(R));
update(R);
return R;
}
}
void insert(int x) {
int L,R;
split(root,x,L,R);
newnode(x);
int aa = merge(L,cnt);
root = merge(aa,R);
}
void del(int x){
int L,R,p;
split(root,x,L,R);
split(L,x-1,L,p);
p = merge(ls(p),rs(p));
root = merge(merge(L,p),R);
}
void rank(int x){
int L,R;
split(root,x-1,L,R);
cout<<t[L].size + 1<<'\n';
root = merge(L,R);
}
int kth(int u,int k) {
if(k == t[ls(u)].size + 1) return u;
if(k <= t[ls(u)].size) return kth(ls(u),k);
if(k > t[ls(u)].size) return kth(rs(u),k - t[ls(u)].size - 1);
}
void pre(int x) {
int L,R;
split(root,x-1,L,R);
cout<<t[kth(L,t[L].size)].key<<'\n';
root = merge(L,R);
}
void suc(int x) {
int L,R;
split(root,x,L,R);
cout<<t[kth(R,1)].key<<'\n';
root = merge(L,R);
}
signed main(){
speed_up(true);
srand(time(NULL));
int n;
cin>>n;
while(n--) {
int opt,x;
cin>>opt>>x;
switch(opt){
case 1:
insert(x);
break;
case 2:
del(x);
break;
case 3:
rank(x);
break;
case 4:
cout<<t[kth(root,x)].key<<'\n';
break;
case 5:
pre(x);
break;
case 6:
suc(x);
break;
}
}
return 0;
}
}
signed main() {
return my::main();
}
Splay:
#include <bits/stdc++.h>
using namespace std;
// 省略了头...
namespace my {
using namespace AllRangeApply_Define;
using namespace Atomic::normalSTD;
//using namespace Atomic::fastSTD;
//using namespace Atomic::SuperSTD;
const int N = 2e5+5;
struct node {
int s[2],p,v,cnt,size;
void init(int p1,int v1) {
p = p1,v = v1;
cnt = size = 1;
}
} t[N];
int root,idx;
void push_up(int x) {
t[x].size = t[t[x].s[0]].size + t[t[x].s[1]].size + t[x].cnt;
}
void rotate(int x) {
int y = t[x].p,z = t[y].p;
int k = t[y].s[1] == x;
t[z].s[t[z].s[1] == y] = x;
t[x].p = z;
t[y].s[k] = t[x].s[k ^ 1];
t[t[x].s[k ^ 1]].p = y;
t[x].s[k^1] = y;
t[y].p = x;
push_up(y),push_up(x);
}
void splay(int x,int k) {
while(t[x].p != k) {
int y = t[x].p,z = t[y].p;
if(z != k) (t[y].s[0] == x) ^ (t[z].s[0] == y) ? rotate(x) : rotate(y);
rotate(x);
}
if(k == 0) root = x;
}
void insert(int v) {
int x = root,p = 0;
while(x && t[x].v != v) {
p = x,x = t[x].s[v > t[x].v];
}
if(x) t[x].cnt++;
else {
x = ++idx;
t[p].s[v > t[p].v] = x;
t[x].init(p,v);
}
splay(x,0);
}
void find(int v) {
int x = root;
while(t[x].s[v > t[x].v] && v != t[x].v) {
x = t[x].s[v > t[x].v];
}
splay(x,0);
}
int get_pre(int v) {
find(v);
int x = root;
if(t[x].v < v) return x;
x = t[x].s[0];
while(t[x].s[1]) x = t[x].s[1];
splay(x,0);
return x;
}
int get_suc(int v) {
find(v);
int x = root;
if(t[x].v > v) return x;
x = t[x].s[1];
while(t[x].s[0]) x = t[x].s[0];
splay(x,0);
return x;
}
void del(int v) {
int pre = get_pre(v);
int suc = get_suc(v);
splay(pre,0),splay(suc,pre);
int del = t[suc].s[0];
if(t[del].cnt > 1) {
t[del].cnt--,splay(del,0);
} else {
t[suc].s[0] = 0;
splay(suc,0);
}
}
int get_rank(int v) {
insert(v);
int res = t[t[root].s[0]].size;
del(v);
return res;
}
int get_val(int k) {
int x = root;
while(1) {
int y = t[x].s[0];
if(t[y].size + t[x].cnt < k) {
k -= t[y].size + t[x].cnt;
x = t[x].s[1];
} else {
if(t[y].size >= k) x = y;
else break;
}
}
splay(x,0);
return t[x].v;
}
int opt,x,n;
signed main() {
speed_up();
insert(-1e18);
insert(1e18);
cin>> n;
while(n--) {
cin>>opt>>x;
switch(opt) {
case 1:
insert(x);
break;
case 2:
del(x);
break;
case 3:
cout<<get_rank(x)<<'\n';
break;
case 4:
cout<<get_val(x + 1)<<'\n';
break;
case 5:
cout<<t[get_pre(x)].v<<'\n';
break;
case 6:
cout<<t[get_suc(x)].v<<'\n';
break;
}
}
return 0;
}
}
signed main() {
return my::main();
}
文艺平衡树
#include <bits/stdc++.h>
using namespace std;
//省略头...
mstart
namespace my{
using namespace AllRangeApply_Define;
using namespace Atomic::normalSTD;
//using namespace Atomic::fastSTD;
//using namespace Atomic::SuperSTD;
const int M = 100005;
namespace artFHQ{
int cnt = 0,root = 0;
struct node{
int ls,rs,pri,key,size,lazy;
}t[M];
#define ls(p) t[p].ls
#define rs(p) t[p].rs
#define pri(p) t[p].pri
#define key(p) t[p].key
#define size(p) t[p].size
#define lazy(p) t[p].lazy
void newnode(int x){
cnt++;
size(cnt) = 1;
ls(cnt) = rs(cnt) = 0;
key(cnt) = x;
pri(cnt) = rand();
// lazy(cnt) = 0;
}
void update(int x){
size(x) = size(ls(x)) + size(rs(x)) + 1;
}
void push_down(int u){
if(lazy(u)){
swap(ls(u),rs(u));
lazy(ls(u)) ^= 1;
lazy(rs(u)) ^= 1;
lazy(u) = 0;
}
}
void spilt(int u,int x,int &L,int &R) {
if(!u) {L = R = 0;return;}
push_down(u);
if(size(ls(u)) + 1 <= x) {
L = u;
spilt(rs(u),x - size(ls(u)) - 1,rs(u),R);
}else {
R = u;
spilt(ls(u),x,L,ls(u));
}
update(u);
}
int merge(int L,int R) {
if(L == 0 || R == 0) return L + R;
if(pri(L) > pri(R)) {
push_down(L);
rs(L) = merge(rs(L),R);
update(L);
return L;
}else {
push_down(R);
ls(R) = merge(L,ls(R));
update(R);
return R;
}
return 0;
}
void inorder(int u) {
if(u == 0) return;
push_down(u);
inorder(ls(u));
cout<<key(u)<<' ';
inorder(rs(u));
}
}
int n,m;
signed main(){
speed_up(true);
srand(time(NULL));
cin>>n>>m;
for(int i = n;i>=1;i--) {
artFHQ::newnode(i);
artFHQ::root = artFHQ::merge(artFHQ::cnt,artFHQ::root);
}
// artFHQ::inorder(artFHQ::root);
// cout<<'\n';
while(m--) {
int x,y;
cin>>x>>y;
int L,R,p;
artFHQ::spilt(artFHQ::root,y,L,R);
artFHQ::spilt(L,x-1,L,p);
artFHQ::lazy(p) ^= 1;
artFHQ::root = artFHQ::merge(artFHQ::merge(L,p),R);
// artFHQ::inorder(artFHQ::root);
}
artFHQ::inorder(artFHQ::root);
return 0;
}
}
mend
signed main() {
return my::main();
}
K-D Tree
K-D Tree (P1429 平面最近点对(加强版))
K-D Tree:
#include <bits/stdc++.h>
using namespace std;
// 省略了头...
namespace my{
using namespace AllRangeApply_Define;
using namespace Atomic::normalSTD;
//using namespace Atomic::fastSTD;
//using namespace Atomic::SuperSTD;
#define lc t[p].l
#define rc t[p].r
const int N = 2e5+10;
double ans = 2e18;
int n,K,root,cur;
struct KD{
int l,r;
double v[2];
double L[2],U[2];
bool operator < (const KD &b) const {return v[K] < b.v[K];}
}t[N];
void push_up(int p) {
for(int i = 0;i<2;i++) {
t[p].L[i] = t[p].U[i] = t[p].v[i];
if(lc) t[p].L[i] = min(t[p].L[i],t[lc].L[i]),t[p].U[i]
= max(t[p].U[i],t[lc].U[i]);
if(rc) t[p].L[i] = min(t[p].L[i],t[rc].L[i]),t[p].U[i]
= max(t[p].U[i],t[rc].U[i]);
}
}
int build(int l,int r,int k) {
if(l > r) return 0;
int m = (l + r) >> 1;
K = k; nth_element(t + l,t + m,t + r + 1);
t[m].l = build(l,m-1,k^1);
t[m].r = build(m + 1,r,k^1);
push_up(m);
return m;
}
double sq(double x) {return x * x;}
double dis(int p) {
double s = 0;
for(int i = 0;i<2;i++) s += sq(t[cur].v[i] - t[p].v[i]);
return s;
}
double dis2(int p) {
if(!p) return 2e18;
double s = 0;
for(int i = 0;i<2;i++) s += sq(max(t[cur].v[i] - t[p].U[i],0.0)) +
sq(max(t[p].L[i] - t[cur].v[i],0.0));
return s;
}
void query(int p) {
if(!p) return;
if(p ^ cur) ans = min(ans,dis(p));
double dl = dis2(lc),dr = dis2(rc);
if(dl < dr) {
if(dl < ans) query(lc);
if(dr < ans) query(rc);
}else {
if(dl < ans) query(lc);
if(dr < ans) query(rc);
}
}
signed main(){
speed_up(false);
scanf("%d",&n);
for(int i = 1;i<=n;i++) scanf("%lf%lf",&t[i].v[0],&t[i].v[1]);
root = build(1,n,0);
for(cur = 1;cur <= n;cur++) query(root);
printf("%.4lf",sqrt(ans));
return 0;
}
}
signed main() {
return my::main();
}
K-D Tree(P4148 简单题)
K-D Tree:
#include <bits/stdc++.h>
using namespace std;
// 省略了头...
namespace my{
using namespace AllRangeApply_Define;
using namespace Atomic::normalSTD;
//using namespace Atomic::fastSTD;
//using namespace Atomic::SuperSTD;
const int N = 5e5+10;
const double alpha = 0.75;
#define lc t[u].ls
#define rc t[u].rs
struct Point{
int dim[2],val;
Point() {}
Point(int x,int y,int v) {dim[0] = x;dim[1] = y;val = v;}
};
Point order[N];
int cnt;
struct node{
int ls,rs;
int mi[2],ma[2];
int sum,size;
Point p;
}t[N];
int tot,root,top,tree_stack[N];// 回收
int now;
bool cmp(Point a,Point b) {return a.dim[now] < b.dim[now];}
void update(int u) {
for(int i = 0;i<2;i++) {
t[u].mi[i] = t[u].ma[i] = t[u].p.dim[i];
if(lc) {
t[u].mi[i] = min(t[u].mi[i],t[lc].mi[i]);
t[u].ma[i] = max(t[u].ma[i],t[lc].ma[i]);
}
if(rc) {
t[u].mi[i] = min(t[u].mi[i],t[rc].mi[i]);
t[u].ma[i] = max(t[u].ma[i],t[rc].ma[i]);
}
}
t[u].size = t[lc].size + t[rc].size + 1;
t[u].sum = t[lc].sum + t[rc].sum + t[u].p.val;
}
// part1_pass
void slap(int u) {
// 拍平
if(!u) return;
slap(lc);
order[++cnt] = t[u].p;
tree_stack[++top] = u;
slap(rc);
}
int build(int l,int r,int d) {
// 建树
if(l > r) return 0;
int u;
if(top) u = tree_stack[top--];
else u = ++tot;
int mid = (l + r) >> 1;
now = d;
nth_element(order + l, order + mid,order + r + 1,cmp);
t[u].p = order[mid];
lc = build(l,mid-1,d ^ 1);
rc = build(mid+1,r,d ^ 1);
update(u);
return u;
}
bool notbalance(int u) {
// 判断平衡
if(t[lc].size > alpha * t[u].size || t[rc].size > alpha * t[u].size) return true;
return false;
}
void insert(int &u,Point now,int d){
if(!u) {
if(top) u = tree_stack[top--];
else u = ++tot;
lc = rc = 0;
t[u].p = now;
update(u);
return;
}
if(now.dim[d] <= t[u].p.dim[d]) insert(lc,now,d ^ 1);
else insert(rc,now,d ^ 1);
update(u);
if(notbalance(u)) {
cnt = 0;
slap(u); // 拍平
u = build(1,t[u].size,d); // 重建
}
}
int query(int u,int x1,int y1,int x2,int y2) {
if(!u) return 0;
int X1 = t[u].mi[0],Y1 = t[u].mi[1],X2 = t[u].ma[0],Y2 = t[u].ma[1];
if(x1 <= X1 && x2 >= X2 && y1 <= Y1 && y2 >= Y2) return t[u].sum; // 完全在矩形内
if(x1 > X2 || x2 < X1 || y1 > Y2 || y2 < Y1) return 0;// 完全在矩阵外
int ans = 0;
X1 = t[u].p.dim[0],Y1 = t[u].p.dim[1],X2 = t[u].p.dim[0],Y2 = t[u].p.dim[1];
if(x1 <= X1 && x2 >= X2 && y1 <= Y1 && y2 >= Y2) ans += t[u].p.val;// 根在矩形内
ans += query(lc,x1,y1,x2,y2) + query(rc,x1,y1,x2,y2); // 递归
return ans;
}
signed main(){
speed_up(true);
int n;
cin>>n;
int ans = 0;
while(1) {
int opt;
cin>>opt;
if(opt == 1) {
int x,y,val;
cin>>x>>y>>val;
x ^= ans,y ^= ans,val ^= ans;
insert(root,Point(x,y,val),0);
}else if(opt == 2) {
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
x1 ^= ans,y1 ^= ans,x2 ^= ans,y2 ^= ans;
ans = query(root,x1,y1,x2,y2);
cout<<ans<<'\n';
}else break;
}
return 0;
}
}
signed main() {
return my::main();
}
笛卡尔树
#include<bits/stdc++.h>
using namespace std;
#define int long long
struct FastIO
{
#define get( ) getchar( )
#define put(x) putchar(x)
public:
inline FastIO &operator >>(char &t) {
t = get(); return *this;
}
inline FastIO &operator >>(char *t) {
while((*t = get()) != '\n') *(++t) = '\0';
return *this;
}
template <typename type>
inline FastIO &operator >>(type &x) {
x = 0; register int sig = 1; register char ch = get();
while (ch < 48 || ch > 57) { if (ch == '-') sig = -1; ch = get(); }
while (ch > 47 && ch < 58) x = (x << 3) + (x << 1) + (ch ^ 48),
ch = get(); x *= sig;
return *this;
}
template <typename type>
inline FastIO &operator <<(type x) {
if (!x) put('0'); if (x < 0) put('-'), x = -x; static char vec[50];
register int len = 0; while (x) vec[len++] = x % 10 + '0', x /= 10;
while (len--) put(vec[len]);
return *this;
}
template <typename type>
inline FastIO &operator <<(type *t) {
for (; *t; t++) put(*t);
return *this;
}
inline FastIO &operator <<(char t) {
put(t);
return *this;
}
}IO;
const int N = 1e7+5;
int n,st[N],A[N],ls[N],rs[N],top = 1;
signed main() {
IO>>n;st[1] = 1;
for(int i = 1;i<=n;i++) IO>>A[i];
for(int i = 2;i<=n;i++){
while(A[st[top]] > A[i] && top) top--; // 建的是小根树,把不等号反向就是大根树
if(!top) ls[i] = st[top + 1];
else ls[i] = rs[st[top]],rs[st[top]] = i;
st[++top] = i;
}
int a = 0,b = 0;
for(int i = 1;i<=n;i++) {
a ^= i * (ls[i] + 1);
b ^= i * (rs[i] + 1);
}
IO<<a<<' '<<b;
return 0;
}
块状链表
#include <bits/stdc++.h>
using namespace std;
// 省略头...
namespace my{
using namespace AllRangeApply_Define;
using namespace Atomic::normalSTD;
//using namespace Atomic::fastSTD;
//using namespace Atomic::SuperSTD;
int block = 2500;
list<vector<char> > List;
typedef list<vector<char> >::iterator it;
it Find(int &pos){
for(it i = List.begin();;i++){
if(i == List.end() || pos <= i -> size()) return i;
pos -= i -> size();
}
}
void Output(int L,int R){
it L_block = Find(L),R_block = Find(R);
for(it it1 = L_block;;it1++) {
int a;it1 == L_block ? a = L:a = 0;
int b;it1 == R_block ? b = R:b = it1->size();
for(int i = a;i<b;i++) putchar(it1->at(i));
if(it1 == R_block) break;
}
putchar('\n');
}
it Next(it x) {return ++x;}
void Merge(it x) {
x -> insert(x ->end(),Next(x)->begin(),Next(x)->end());
List.erase(Next(x));
}
void Spilt(it x,int pos){
if(pos == x ->size()) return;
List.insert(Next(x),vector<char>(x->begin() + pos,x->end()));
x ->erase(x->begin() + pos,x -> end());
}
void update() {
for(it i = List.begin();i != List.end();i++) {
while(i -> size() >= (block << 1)) Spilt(i,i -> size() - block);
while(Next(i) != List.end() && i ->size() + Next(i) -> size() <= block) Merge(i);
while(Next(i) != List.end() && Next(i) -> empty()) List.erase(Next(i));
}
}
void Insert(int pos,const vector<char> &ch){
it curr = Find(pos);
if(!List.empty()) Spilt(curr,pos);
List.insert(Next(curr),ch);
update();
}
void Delete(int L,int R){
it L_block,R_block;
L_block = Find(L);Spilt(L_block,L);
R_block = Find(R);Spilt(R_block,R);
R_block++;
while(Next(L_block) != R_block) List.erase(Next(L_block));
update();
}
signed main(){
speed_up(false);
vector<char> ch;int len,pos,n;
cin>>n;
while(n--) {
char opt[7];
cin>>opt;
if(opt[0] == 'M') cin>>pos;
if(opt[0] == 'I') {
ch.clear();
cin>>len;
ch.resize(len);
for(int i = 0;i<len;i++) {
ch[i] = getchar();
while(ch[i] < 32 || ch[i] > 126) ch[i] = getchar();
}
Insert(pos,ch);
}
if(opt[0] == 'D') {cin>>len; Delete(pos,pos + len);}
if(opt[0] == 'G') {cin>>len; Output(pos,pos + len);}
if(opt[0] == 'P') {pos--;}
if(opt[0] == 'N') {pos++;}
}
return 0;
}
}
signed main() {
return my::main();
}