• [练习记录]数据结构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
    */
    
    
  • 相关阅读:
    高斯消元法
    DP:Making the Grade(POJ 3666)
    Heap:Sunscreen(POJ 3614)
    ShortestPath:Silver Cow Party(POJ 3268)
    ShortestPath:Wormholes(POJ 3259)
    ShortestPath:Six Degrees of Cowvin Bacon(POJ 2139)
    DP:Bridging Signals(POJ 1631)
    DP:Wooden Sticks(POJ 1065)
    Greedy:Protecting the Flowers(POJ 3262)
    Greedy:Stripes(POJ 1826)
  • 原文地址:https://www.cnblogs.com/dixiao/p/15868485.html
Copyright © 2020-2023  润新知