【模板】資料結構

ft61發表於2024-08-17

資料結構

  • 權值 BIT 上二分
struct {
    int n,t[N];
	int kth(int k) {
		int p = 0;
        rFor(i,__lg(n),0) if( p+(1<<i) < n && k > t[p+(1<<i)] ) p += 1<<i, k -= t[p];
		return p+1;
	}
} ;
  • zkw 線段樹

  • 李超線段樹

  • 線段樹合併,分裂

  • 可持久化 \(01\)Trie

值域 \([0,2^{30})\)

struct {
	int ind,rt[N],ch[N*31][2],siz[N*31];
	void ins(int u,int v,int x) {
		u = rt[u], v = rt[v] = ++ind;
		rFor(i,29,0) {
			bool y = x>>i&1;
			ch[v][!y] = ch[u][!y], u = ch[u][y], v = ch[v][y] = ++ind,
			siz[v] = siz[u] + 1;
		}
	}
	int qry(int u,int v,int x) {
		u = rt[u], v = rt[v];
		int res = 0;
		for(int i = 1<<29; i; i >>= 1) {
			bool y = ~x&i;
			if( siz[ch[u][y]] < siz[ch[v][y]] ) res |= i, u = ch[u][y], v = ch[v][y];
			else u = ch[u][!y], v = ch[v][!y];
		}
		return res;
	}
} ;
  • 笛卡爾樹

升序 BST 以 \(i\) 為權值,小根堆以 \(a[i]\) 為權值

void bld() {
	For(i,1,n) {
		int tmp = tp;
		while( tp && a[i] < a[stk[tp]] ) --tp;
		if( tp ) ch[stk[tp]][1] = i;
		if( tp < tmp ) ch[i][0] = stk[tp+1];
		stk[++tp] = i;
	}
}
  • 可持久化文藝平衡樹

空間限制 \(256\)MB

// LG5586 [P5350] 序列 (加強版)
#define ls(u) t[u].ch[0]
#define rs(u) t[u].ch[1]
const int N = 3e5+5, M = 5e6;
int ind,rt,n,a[N],len[N];
struct Node { int ch[2],siz,len; mint val,sum,add; bool rev; } t[M+N];
int node(int len,mint x)
	{ return t[++ind] = {0,0,len,len,x,len*x,0,0}, ind; }
int node(const Node &x){ return t[++ind] = x, ind; }
void up(int u) {
	t[u].siz = t[ls(u)].siz + t[rs(u)].siz + t[u].len,
	t[u].sum = t[ls(u)].sum + t[rs(u)].sum + t[u].len*t[u].val;
}
void down(int u,mint x,bool y) {
	if( x.x ) t[u].val += x, t[u].add += x, t[u].sum += t[u].siz * x;
	if( y ) t[u].rev ^= y, swap(ls(u),rs(u));
}
void down(int u) { if( t[u].add.x || t[u].rev ) {
	if( ls(u) ) down( ls(u)=node(t[ls(u)]) ,t[u].add,t[u].rev);
	if( rs(u) ) down( rs(u)=node(t[rs(u)]) ,t[u].add,t[u].rev);
	t[u].add = t[u].rev = 0;
}}
void dfs(int u) {
	down(u);
	if( ls(u) ) dfs(ls(u));
	if( n && a[n] == t[u].val.x ) len[n] += t[u].len;
	else a[++n] = t[u].val.x, len[n] = t[u].len;
	if( rs(u) ) dfs(rs(u));
}
int bld(int l=1,int r=n) {
	if( l > r ) return 0;
	int mid = l+r>>1, u = node(len[mid],a[mid]);
	return ls(u) = bld(l,mid-1), rs(u) = bld(mid+1,r), up(u), u;
}
void rbld() { n = 0, dfs(rt), ind = 0, rt = bld(); }
void split(int u,int k,int &l,int &r) {
	if( !u ) { l = r = 0; return; }
	down(u);
	if( t[ls(u)].siz < k && k < t[ls(u)].siz+t[u].len ) {
		int mid = k-t[ls(u)].siz, v = node(t[u]);
		t[v].len = t[u].len-mid, t[u].len = mid;
		ls(v) = 0, rs(u) = v, up(v), up(u);
	}
	if( k <= t[ls(u)].siz ) r = node(t[u]), split(ls(r),k,l,ls(r)), up(r);
	else l = node(t[u]), split(rs(l),k-t[ls(l)].siz-t[l].len,rs(l),r), up(l);
}
int merge(int l,int r) {
	if( !l || !r ) return l | r;
	int u;
	if( mt()%(t[l].siz+t[r].siz) < t[l].siz )
		down(u=node(t[l])), rs(u) = merge(rs(u),r);
	else down(u=node(t[r])), ls(u) = merge(l,ls(u));
	return up(u), u;
}
mint sum(int l,int r) { // ask sum of [l,r]
	int a,b,c; split(rt,r,b,c), split(b,l-1,a,b);
	mint res = t[b].sum;
	rt = merge(merge(a,b),c);
	return res;
}
void cov(int l,int r,int x) { // let [l,r] = x
	int a,b,c; split(rt,r,b,c), split(b,l-1,a,b);
	rt = merge(merge(a,node(r-l+1,x)),c);
}
void add(int l,int r,int x) { // let [l,r] += x
	int a,b,c; split(rt,r,b,c), split(b,l-1,a,b);
	down(b,x,0);
	rt = merge(merge(a,b),c);
}
void copy(int l1,int r1,int l2,int r2) { // let [l2,r2] = [l1,r1]
	int a,b,c,d,e; bool flg = 0;
	if( l1 > l2 ) swap(l1,l2), swap(r1,r2), flg = 1;
	split(rt,r2,d,e), split(d,l2-1,c,d), split(c,r1,b,c), split(b,l1-1,a,b);
	rt = merge(merge(merge(merge(a,!flg?b:d),c),!flg?b:d),e);
}
void swap(int l1,int r1,int l2,int r2) { // swap [l1,r1] and [l2,r2]
	if( l1 > l2 ) swap(l1,l2), swap(r1,r2);
	int a,b,c,d,e;
	split(rt,r2,d,e), split(d,l2-1,c,d), split(c,r1,b,c), split(b,l1-1,a,b);
	rt = merge(merge(merge(merge(a,d),c),b),e);
}
void rev(int l,int r) { // reverse [l,r]
	int a,b,c; split(rt,r,b,c), split(b,l-1,a,b);
	down(b,0,1);
	rt = merge(merge(a,b),c);
}
void dbg() {
	n = 0, dfs(rt);
	For(i,1,n, p = 1) {
		if( len[i] > 1 ) cerr<<"["<<p<<","<<p+len[i]-1<<"]:";
		cerr<<a[i]<<(i<n?' ':'\n');
		p += len[i];
	}
}
signed main() {
	cin>>n>>m; For(i,1,n) cin>>a[i], len[i] = 1;
	rt = bld();
	while( m-- ) {
		
		if( ind >= M ) rbld();
//		dbg();
	}
	n = 0, dfs(rt); For(i,1,n) For(j,1,len[i]) cout<<a[i]<<" ";
}
  • KDT

  • LCT

#define ls(u) t[u].ch[0]
#define rs(u) t[u].ch[1]
struct {
	struct Node { int fa,ch[2]; bool rev; } t[];
	void rev(int u) { swap(ls(u),rs(u)), t[u].rev ^= 1; }
	void down(int u) { if( t[u].rev ) rev(ls(u)), rev(rs(u)), t[u].rev = 0; }
	bool nrt(int u) { return ls(t[u].fa)==u || rs(t[u].fa)==u; }
	bool wh(int u) { return rs(t[u].fa)==u; }
	void rotate(int x) {
		int y = t[x].fa, z = t[y].fa, k = wh(x), w = t[x].ch[!k];
		if( nrt(y) ) t[z].ch[wh(y)] = x; t[x].ch[!k] = y, t[y].ch[k] = w;
		t[w].fa = y, t[y].fa = x, t[x].fa = z;
	}
	void splay(int u) {
		static int tp,stk[N];
		for(int v = stk[tp=1] = u; nrt(v); stk[++tp] = v = t[v].fa);
		while( tp ) down(stk[tp--]);
		for(int fa; fa = t[u].fa, nrt(u); rotate(u))
			if( nrt(fa) ) rotate(wh(fa)==wh(u)?fa:u);
	}
	void access(int x) {
		for(int u = x, v = 0; u; u = t[v=u].fa) splay(u), rs(u) = v;
		splay(x);
	}
	void mkrt(int u) { access(u), rev(u); }
	int fdrt(int u) {
		access(u);
		while( ls(u) ) down(u), u = ls(u);
		return splay(u), u;
	}
	void split(int u,int v) { mkrt(u), access(v); }
	void link(int u,int v) { mkrt(u), t[u].fa = v; }
	void cut(int u,int v) { split(u,v), t[u].fa = ls(v) = 0; }
} ;
  • 珂朵莉樹
struct CT {
	int l,r;
	mutable int val;
	CT(int l=0,int r=0,int val=0):l(l),r(r),val(val){}
	bool operator < (const CT &rhs) const { return l < rhs.l; }
}; set<CT> ct;
auto split(int p) {
	auto it = --ct.upper_bound({p});
	if( it->l == p ) return it;
	int l = it->l, r = it->r, x = it->val;
	ct.erase(it), ct.emplace(l,p-1,x);
	return ct.emplace(p,r,x).fi;
}
void assign(int l,int r,int x) {
	auto itr = split(r+1), itl = split(l);
	// if( itr != ct.end() && x == itr->val ) r = (itr++)->r;
	// if( itl != ct.begin() && x == prev(itl)->val) l = (--itl)->l;
	ct.erase(itl,itr), ct.emplace(l,r,x);
}
  • 壓位 trie

值域 \([0,2^{20})\)

// bzoj3685 普通van Emde Boas樹
#define ctz(x) (uLL)__builtin_ctzll(x)
#define clz(x) (uLL)__builtin_clzll(x)
struct Trie {
	uLL *t[4];
	Trie() {
		t[0] = new uLL[1<<14](), t[1] = new uLL[1<<8](),
		t[2] = new uLL[1<<2](), t[3] = new uLL[1<<0]();
	}
	void ins(int x) {
		Rep(i,0,4) {
			uLL &u = t[i][x>>(i+1)*6], e = 1ull<<(x>>i*6&63);
			if( u & e ) return; u |= e;
		}
	}
	void ers(int x)
        { Rep(i,0,4) if( t[i][x>>(i+1)*6] &= ~(1ull<<(x>>i*6&63)) ) return; }
	int min() {
		if( !t[3][0] ) return -1;
		int u = 0; rFor(i,3,0) u |= ctz(t[i][u>>(i+1)*6]) << i*6;
		return u;
	}
	int max() {
		if( !t[3][0] ) return -1;
		int u = 0; rFor(i,3,0) u |= 63-clz(t[i][u>>(i+1)*6]) << i*6;
		return u;
	}
	int suf(int x) {
		Rep(i,0,4) {
			int e = x>>i*6&63; uLL u = t[i][x>>(i+1)*6];
			if( u>>e > 1 ) {
				int res = x >> (i+1)*6 << (i+1)*6;
				res |= ctz(u>>e+1)+e+1 << i*6;
				rFor(j,i-1,0) res |= ctz(t[j][res>>(j+1)*6]) << j*6;
				return res;
			}
		}
		return -1;
	}
	int pre(int x) {
		Rep(i,0,4) {
			int e = x>>i*6&63; uLL u = t[i][x>>(i+1)*6];
			if( u & (1ull<<e)-1 ) {
				int res = x >> (i+1)*6 << (i+1)*6;
				res |= 63-clz(u&(1ull<<e)-1) << i*6;
				rFor(j,i-1,0) res |= 63-clz(t[j][res>>(j+1)*6]) << j*6;
				return res;
			}
		}
		return -1;
	}
	int qry(int x) { return t[0][x>>6] & 1ull<<(x&63) ? 1 : -1; }
} ;

塊狀

  • 塊狀連結串列,值域分塊

值域同序列長度

// LG4278 帶插入區間K小值
const int N = 7e4+5, B = 512, BN = N/B+5;
struct DS { // 值域分塊
	int sum[BN],cnt[N];
	void add(int x,int y) { sum[x/B] += y, cnt[x] += y; }
};
struct Blk : Vi {
	DS ds;
	void ins(int i,int x) { emplace(begin()+i,x), ds.add(x,1); }
}; vector<Blk> bk(1); // 塊狀連結串列

Pii find(int p) { // 塊狀連結串列定位 p 位置
	Rep(i,0,sz(bk))
		if( p < sz(bk[i]) ) return {i,p};
		else p -= sz(bk[i]);
	return {sz(bk)-1,sz(bk.back())};
}

void ins(int p,int x) { // p 位置前插入 x
	int i,j; tie(i,j) = find(p);
	bk[i].ins(j,x);
	Rep(k,i+1,sz(bk)) bk[k].ds.add(x,1);
	if( sz(bk[i]) > 2*B ) {
		Vi a(bk[i].end()-B,bk[i].end());
		bk[i].erase(bk[i].end()-B,bk[i].end()),
		bk.emplace(bk.begin()+i+1,Blk()), bk[i+1].ds = bk[i].ds;
		for(int k : a) bk[i].ds.add(k,-1), bk[i+1].pb(k);
	}
}
void mdf(int p,int x) { // p 位置的值改為 x
	int i,j; tie(i,j) = find(p);
	int y = bk[i][j]; bk[i][j] = x;
	Rep(k,i,sz(bk)) bk[k].ds.add(x,1), bk[k].ds.add(y,-1);
}
int qry(int l,int r,int x) { // 查詢 [l,r] 第 x 小
	static DS ds;
	int li,lj,ri,rj; tie(li,lj) = find(l), tie(ri,rj) = find(r);
	auto add=[&](int y) {
		if( li == ri ) For(i,lj,rj) ds.add(bk[li][i],y);
		else {
			Rep(i,lj,sz(bk[li])) ds.add(bk[li][i],y);
			For(i,0,rj) ds.add(bk[ri][i],y);
		}
	};
	add(1);
	for(int i = 0; ; ++i) {
		int y = ds.sum[i] + (li<ri?bk[ri-1].ds.sum[i]-bk[li].ds.sum[i]:0);
		if( x > y ) x -= y;
		else {
			i = i*B-1;
			do
				++i,
				x -= ds.cnt[i] + (li<ri?bk[ri-1].ds.cnt[i]-bk[li].ds.cnt[i]:0);
			while( x > 0 );
			add(-1);
			return i;
		}
	}
}

相關文章