模板大合集 - Part 1

树状数组

#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;
}


区间历史最大值线段树

P4314 CPU监控

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!]

P8868 [NOIP2022] 比赛

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 xy 处 的线段树 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 lsrs 的答案

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

块状链表

P4008 [NOI2003] 文本编辑器

#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();
}
  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值