[练习记录]数据结构2(可持久化,树套树)

P3835 【模板】可持久化平衡树

版版题。

P3835 【模板】可持久化平衡树
// code by fhq_treap
#include<bits/stdc++.h>
#define ll long long
#define N 500005

inline ll read(){
    char C=getchar();
    ll A=0 , F=1;
    while(('0' > C || C > '9') && (C != '-')) C=getchar();
    if(C == '-') F=-1 , C=getchar();
    while('0' <= C && C <= '9') A=(A << 1)+(A << 3)+(C - 48) , C=getchar();
    return A*F;
}

template <typename T>
void write(T x)
{
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        write(x/10);
    putchar(x % 10 + '0');
    return;
}

struct P{
	int l,r;
	int siz,rnd,v;
}T[N * 50];

#define ls(x) T[x].l
#define rs(x) T[x].r
#define s(x) T[x].siz
#define c(x) T[x].rnd
#define v(x) T[x].v

inline void up(int x){s(x) = s(ls(x)) + s(rs(x)) + 1;}

int cnt;

inline int newn(int x){return v(++cnt) = x,c(cnt) = rand(),s(cnt) = 1,cnt;}

#define update up

inline int merge(int x,int y){
	if(!x || !y)return x ^ y;
	if(c(x) > c(y)){//持久化
		int p = ++ cnt;
		T[p] = T[x];
		rs(p) = merge(rs(p),y);
		return up(p),p;
	}else{
		int p = ++ cnt;
		T[p] = T[y];
		ls(p) = merge(x,ls(p));
		return up(p),p;
	}
}

inline void split(int now,int k,int &x,int &y){
	if(!now)return void(x = y = 0);
	else{
		if(v(now) <= k){
			x = ++cnt;
			T[x] = T[now];
			split(rs(x),k,rs(x),y);
			up(x);
		}else{
			y = ++cnt;
			T[y] = T[now];
			split(ls(y),k,x,ls(y));
			up(y);
		}
	}
}

inline void del(int &root,int w){
	int x,y,z;x = y = z = 0;
	split(root,w,x,z);
	split(x,w - 1,x,y);
	y = merge(ls(y),rs(y));
	root = merge(merge(x,y),z);
}

inline void ins(int &root,int w){
	int x,y,z;x = y = z = 0;
	split(root,w,x,y);
	z = newn(w);
	root = merge(merge(x,z),y);
}

inline int getval(int k,int w){
	if(w == s(ls(k)) + 1)return v(k);
	else if(w <= s(ls(k)))return getval(ls(k),w);
	else return getval(rs(k),w - s(ls(k)) - 1);
}

inline int getkth(int &root,int w){
	int x,y;
	split(root,w - 1,x,y);
	int ans = s(x) + 1;
	root = merge(x,y);
	return ans;
}

inline int getpre(int &root,int w){
	int x,y;
	split(root,w - 1,x,y);
	if(!x)return -2147483647;
	int ans = getval(x,s(x));
	root = merge(x,y);
	return ans;
}

inline int getnex(int &root,int w){
    int x,y,ans;
    split(root,w,x,y);
    if(!y)return 2147483647;
    else ans=getval(y,1);
    root=merge(x,y);
    return ans;
}

int rt[N];
int n,w,las,f;

int main(){
	srand(time(0));
	scanf("%d",&n);
	for(int i = 1;i <= n;++i){
		scanf("%d%d%d",&las,&f,&w);
		rt[i] = rt[las];
		if(f == 1)ins(rt[i],w);
		if(f == 2)del(rt[i],w);
		if(f == 3)std::cout<<getkth(rt[i],w)<<"\n";
		if(f == 4)std::cout<<getval(rt[i],w)<<"\n";
		if(f == 5)std::cout<<getpre(rt[i],w)<<"\n";
		if(f == 6)std::cout<<getnex(rt[i],w)<<"\n";
	}
}


CF1340F Nastya and CBS

考虑用分块维护块内的合并结果。
若能成功合并则最后的结果一定为若干右括号加上若干左括号。
考虑块间合并时不使用hash,发现题解区有老哥使用了暴力合并的方法。

CF1340F Nastya and CBS
/// code by fhq_treap
#include<bits/stdc++.h>
#define ll long long
#define N 100005

inline ll read(){
    char C=getchar();
    ll A=0 , F=1;
    while(('0' > C || C > '9') && (C != '-')) C=getchar();
    if(C == '-') F=-1 , C=getchar();
    while('0' <= C && C <= '9') A=(A << 1)+(A << 3)+(C - 48) , C=getchar();
    return A*F;
}

template <typename T>
void write(T x)
{
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        write(x/10);
    putchar(x % 10 + '0');
    return;
}

bool begin;

#define S 350

int n,k,m;
int a[N];
int B;
int in[N],li[N],ri[N];

int L[S][S],R[S][S];//合并结果

int ma[N];//匹配结果

int stk[N],top;

inline void up(int x){
//	std::cout<<"DEL BLOCK"<<x<<" "<<li[x]<<" "<<ri[x]<<std::endl;
	ma[x] = 1,L[x][0] = R[x][0] = 0,top = 0;
	for(int i = li[x];i <= ri[x];++i){
		if(a[i] > 0)
		stk[++top] = a[i];
		else
		{
			if(top > 0){
				if(stk[top -- ] != -a[i]){
					ma[x] = 0;
					break;
				}
			}else{
				L[x][++L[x][0]] = a[i];
			}
		}
	}
	memcpy(R[x] + 1,stk + 1,top * sizeof(int));
	R[x][0] = top;
//	if(!ma[x])std::cout<<"FUCK\n"<<std::endl;
//	else{
//	std::cout<<"the Left of Right match"<<"\n";
//	std::cout<<L[x][0]<<std::endl;
//	for(int i = 1;i <= L[x][0];++i)
//	std::cout<<L[x][i]<<" ";
//	puts("");
//	std::cout<<"the Right of Left match"<<"\n";
//	std::cout<<R[x][0]<<std::endl;
//	for(int i = 1;i <= R[x][0];++i)
//	std::cout<<R[x][i]<<" ";
//	puts("");
//	puts("");
//	}
}

inline void init(){
	B = sqrt(n);
//	std::cout<<B<<std::endl;
	for(int i = 1;i <= n;++i)
	in[i] = (i - 1) / B + 1,li[i] = n + 1,ri[i] = 0;
	for(int i = 1;i <= n;++i)
	li[in[i]] = std::min(i,li[in[i]]),ri[in[i]] = std::max(ri[in[i]],i);
	for(int i = 1;i <= in[n];++i)
	up(i);
}

inline bool ask(int l,int r){
	top = 0;
	if(in[l] == in[r]){
		for(int i = l;i <= r;++i){
		if(a[i] > 0)
		stk[++top] = a[i];
		else
		if(!top || stk[top -- ] != -a[i])
		return 0;
		}
		return !top;
	}
	for(int i = l;i <= ri[in[l]];++i)
	if(a[i] > 0) stk[++top] = a[i];
	else if(!top || stk[top -- ] != -a[i]) return 0;
//	puts("THE MID BLOCK");
	for(int i = in[l] + 1;i <= in[r] - 1;++i){
		if(!ma[i])return 0;
		if(top < L[i][0])return 0;
		for(int j = 1;j <= L[i][0];++j){;
		if(!top || stk[top -- ] != -L[i][j])
		return 0;
		}
		memcpy(stk + 1 + top,R[i] + 1,R[i][0] * sizeof(int)),top += R[i][0];
	}
	for(int i = li[in[r]];i <= r;++i)
	if(a[i] > 0) stk[++top] = a[i];
	else if(!top || stk[top -- ] != -a[i]) return 0;
	return !top;
}

bool end;

int main(){
//	std::cout<<(&end - &begin) / 1024 / 1024;
	scanf("%d%d",&n,&k);
	for(int i = 1;i <= n;++i)
	a[i] = read();
	init();
	int m = read();
	while(m -- ){
		int opt = read(),x = read(),y = read();
		if(opt == 1){
			a[x] = y;
			up(in[x]);
		}else{
			puts(ask(x,y) ? "Yes" : "No");
		}
	}
}


P7561 [JOISC 2021 Day2] 道路の建設案

考虑曼哈顿转切比雪夫\((x,y) -> (x + y,x - y)\),然后二分,发现变成了这个二维数点,我们直接扫描线。

P2824 [HEOI2016/TJOI2016]排序

考虑二分,按大小处理出01串,然后把排序变成区间赋值即可。

P2824 [HEOI2016/TJOI2016]排序
// Problem: P2824 [HEOI2016/TJOI2016]排序
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2824
// Memory Limit: 256 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long 
#define N 100005

ll t[N << 2],num[N],tag[N];//维护1的数量

#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
#define mid ((l + r) >> 1)

ll n,m,p;

struct P{
	ll l,r,opt;
}q[N];


inline void up(int u){
	t[u] = t[ls(u)] + t[rs(u)];
}

inline void build(int u,int l,int r,int x){
	if(l == r){
		t[u] = num[l] >= x;
		return;
	}
	build(ls(u),l,mid,x);
	build(rs(u),mid + 1,r,x);
	up(u);
}

inline void del(int u,int len){
	if(tag[u] == 1){
		t[u] = 0;
		return;
	}
	if(tag[u] == 2){
		t[u] = len;
		return ;
	}
}

inline void down(int u,int l,int r){
	if(tag[u]){
		tag[ls(u)] = tag[u];
		tag[rs(u)] = tag[u];
		del(ls(u),mid - l + 1);
		del(rs(u),r - mid);
		tag[u] = 0;
	}
}

inline void change(int u,int l,int r,int tl,int tr,int to){
	if(tl > tr)
	return;
	if(tl <= l && r <= tr){
		tag[u] = to;
		del(u,r - l + 1);
		return;
	}
	down(u,l,r);
	if(tl <= mid)
	change(ls(u),l,mid,tl,tr,to);
	if(tr > mid)
	change(rs(u),mid + 1,r,tl,tr,to);
	up(u);
	return;
}

inline ll que(int u,int l,int r,int tl,int tr){
	if(tl <= l && r <= tr)
		return t[u];
	ll ans = 0;
	down(u,l,r);
	if(tl <= mid)
	ans += que(ls(u),l,mid,tl,tr);
	if(tr > mid)
	ans += que(rs(u),mid + 1,r,tl,tr);
	return ans;
}

//1 2 5 6 3 4
//1 2 6 5 4 3
//1 2 5 

inline bool check(int x){
	std::memset(tag,0,sizeof(tag));
	std::memset(t,0,sizeof(t));
	build(1,1,n,x);
	for(int i = 1;i <= m;++i){
		ll cnt = que(1,1,n,q[i].l,q[i].r);
		if(q[i].opt == 1){//降序
			change(1,1,n,q[i].l,q[i].l + cnt - 1,2);//1
			change(1,1,n,q[i].l + cnt,q[i].r,1);
		}else{
			cnt = q[i].r - q[i].l + 1 - cnt;
			change(1,1,n,q[i].l,q[i].l + cnt - 1,1);//1
			change(1,1,n,q[i].l + cnt,q[i].r,2);			
		}
	}
	return que(1,1,n,p,p);
}

int main(){
	scanf("%lld%lld",&n,&m);
	for(int i = 1;i <= n;++i)
	scanf("%lld",&num[i]);
	for(int i = 1;i <= m;++i)
	scanf("%lld%lld%lld",&q[i].opt,&q[i].l,&q[i].r);
	scanf("%lld",&p);
	ll l = 1,r = n;
	ll ans = 0;
	while(l + 1 <= r){
		if(check(mid))
			ans = mid,l = mid + 1;
		else
			r = mid - 1;
	}
	while(check(ans + 1))
	ans = ans + 1;
	std::cout<<ans<<std::endl;
}

P7834 [ONTAK2010] Peaks 加强版

考虑使用Kruskal重构树。

然后可以转为查询子树内第\(k\)大点权叶子,可以对\(dfn\)序维护主席树,或者直接线段树合并都可以。

P7834 [ONTAK2010] Peaks 加强版
#include<bits/stdc++.h>
#define ll long long 
#define N 500005

struct P{
	int x,y,v;
}e[N];

bool operator < (P a,P b){
	return a.v < b.v;
}

int f[N];

int n,m;

inline int find(int x){return (x == f[x] ? x : f[x] = find(f[x]));}

int las = 0;

struct Seg{
	int l,r;
	ll siz;
}T[N * 20];

ll a[N];
int pcnt;

using std::vector;

vector<int>A[N];

int fa[N][30];
int dfn[N],end[N],inv[N];
int dfncnt;

inline void dfs(int u,int fi){
	fa[u][0] = fi;
	dfn[u] = end[u] = ++dfncnt;
//	std::cout<<u<<" "<<dfn[u]<<std::endl;
	inv[dfn[u]] = u;
	for(int i = 1;i <= 20;++i)
	fa[u][i] = fa[fa[u][i - 1]][i - 1];
	for(int i = 0;i < A[u].size();++i){
		int v = A[u][i];
		dfs(v,u);
		end[u] = std::max(end[u],end[v]);
	}
}

int head[N];

#define s(x) T[x].siz
#define ls(x) T[x].l
#define rs(x) T[x].r
#define mid ((l + r) >> 1)

int segcnt;

inline void change(int las,int &now,int l,int r,int k){
	if(!now) now = ++segcnt;
//	std::cout<<las<<" "<<now<<" "<<l<<" "<<r<<" "<<k<<std::endl; 
	T[now] = T[las];
	s(now) ++ ;
	if(l == r)return ;
	if(k <= mid){
		ls(now) = 0;
		change(ls(las),ls(now),l,mid,k);
	}else{
		rs(now) = 0;
		change(rs(las),rs(now),mid + 1,r,k);
	}
}

int q;

#define inf 1000000005

inline int query(int las,int now,int l,int r,int k){
//	std::cout<<las<<" "<<now<<" "<<l<<" "<<r<<" "<<k<<std::endl;
	if(s(now) - s(las) < k)
	return -1;
	if(l == r)return l;
	if(s(rs(now)) - s(rs(las)) >= k)
	return query(rs(las),rs(now),mid + 1,r,k);
	else
	return query(ls(las),ls(now),l,mid,k - (s(rs(now)) - s(rs(las))));
}

int main(){
//	freopen("q.out","w",stdout);
	scanf("%d%d%d",&n,&m,&q);
	for(int i = 1;i <= n;++i)
	scanf("%d",&a[i]),f[i] = i;
	for(int i = 1;i <= 2 * n;++i)
	f[i] = i;
	for(int i = 1;i <= m;++i)
		scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);
	std::sort(e + 1,e + m + 1);
	pcnt = n;
	for(int i = 1;i <= m;++i){
		int x = e[i].x,y = e[i].y;
		int fx = find(x),fy = find(y);
//		std::cout<<"("<<e[i].x<<" "<<e[i].y<<" "<<e[i].v<<" "<<fx<<" "<<fy<<")"<<std::endl; 
		if(fx != fy){
			a[++pcnt] = e[i].v;
//			std::cout<<pcnt<<" "<<fx<<std::endl;
//			std::cout<<pcnt<<" "<<fy<<std::endl;	 
			A[pcnt].push_back(fx);
			A[pcnt].push_back(fy);
			f[fx] = pcnt,f[fy] = pcnt;
		}
	}
	dfs(pcnt,0);
	for(int i = 1;i <= dfncnt;++i){
//		std::cout<<"DEL "<<i<<" "<<inv[i]<<"\n";
		if(inv[i] <= n){
			change(head[i - 1],head[i],1,inf,a[inv[i]]);
		}else{
			head[i] = head[i - 1];
		}
	}
	a[0] = inf * 100ll;
	int las = 0;
	while(q -- ){
		int u,x,k;
		scanf("%d%d%d",&u,&x,&k);
		if(las == -1)las = 0;
		u ^= las,x ^= las,k ^= las;
		u = (u % n) + 1,k = (k % n) + 1; 
//		std::cout<<u<<" "<<x<<" "<<k<<std::endl; 		
		for(int i = 20;i >= 0;--i){
			if(a[fa[u][i]] <= x)
			u = fa[u][i];
		}
//		std::cout<<u<<std::endl;
		std::cout<<(las = query(head[dfn[u] - 1],head[end[u]],1,inf,k))<<"\n";
	}
}
/*
10 11 3
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6

0 5 5
1 6 8
7 8 1
*/

posted @ 2022-02-07 16:58  fhq_treap  阅读(79)  评论(0编辑  收藏  举报