luogu P4200 千山鸟飞绝 题解 【一维数组套平衡树】

题目

题目链接

解题思路

首先,此题有明显的插入、删除、查找,所以必须要使用平衡树。
考虑如何使用平衡树维护每个鸟的状态。发现很不方便,因为鸟的位置改变,整个平衡树的值都要修改。
考虑针对每个节点开一颗平衡树,这样就有3e4×3e4棵树。这显然太多了,考虑离散化。
可以使用map存储。
细节很多,但是有很多收获:val[]在相同时可以直接插入。

code

#include<iostream>
#include<cstdio>
#include<map>
using namespace std ;
#define pii pair<int,int>
const int MAXN = 3e5+10 ;

int siz[MAXN] ,ch[MAXN][2] ,val[MAXN] ,w[MAXN] ,q[MAXN] ,a[MAXN] ;
int fa[MAXN] ,rt[MAXN] ,tot = 0 ;
int slazy[MAXN] ,wlazy[MAXN] ,ans1[MAXN] ,ans2[MAXN] ;

inline void maintain(int x){
	siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1 ;
	val[x] = max(max(val[ch[x][0]] , val[ch[x][1]]) , w[x]) ;
} 

inline bool islrch(int x){
	return ch[fa[x]][1] == x ;
}

inline void clear(int x){
	siz[x] = ch[x][1] = ch[x][0] = val[x] = fa[x] = slazy[x] = wlazy[x] = 0 ;
}

inline void rotate(int x){
	int y = fa[x] ,z = fa[y] ;
	int chk = islrch(x) ;
	ch[y][chk] = ch[x][chk ^ 1] ;
	fa[ch[x][chk ^ 1]] = y ;
	ch[x][chk ^ 1] = y ;
	fa[y] = x ;
	fa[x] = z ;
	if(z)	ch[z][ch[z][1] == y] = x ;
	maintain(y) ;
	maintain(x) ;
}

inline void pushdown(int x){
	int k1 = wlazy[x] ,k2 = slazy[x] ;
	for(int i = 0;i < 2;++i)
		if(ch[x][i]){
			int c = ch[x][i] ;
			ans1[c] = max(ans1[c] , k1) ;
			ans2[c] = max(ans2[c] , k2) ;
			wlazy[c] = max(k1 , wlazy[c]) ;
			slazy[c] = max(k2 , slazy[c]) ;
		}
	slazy[x] = wlazy[x] = 0 ;
}

int stack[MAXN] ,topp = 0 ;
inline int splay(int x){
	for(int i = x;i;i = fa[i])	stack[++topp] = i ;
	while(topp)	pushdown(stack[topp--]) ;
	for(int f = fa[x];f = fa[x] ,f;rotate(x))
		if(fa[f])	rotate(islrch(f) == islrch(x) ? f : x) ;
	return x ;
}

inline int pre(int x){
	int cur = ch[rt[x]][0] ;
	while(ch[cur][1])	cur = ch[cur][1] ;
	rt[x] = splay(cur) ;
	return cur ;
}

inline void del(int r , int x){
	rt[r] = splay(x) ;
	if(!ch[rt[r]][0] && !ch[rt[r]][1]){
		clear(rt[r]) ;
		rt[r] = 0 ;
		return ;
	}
	if(!ch[rt[r]][0]){
    	int cur = rt[r] ;
    	rt[r] = ch[rt[r]][1] ;
    	fa[rt[r]] = 0 ;
    	clear(cur) ;
    	return ;
  	}
	if(!ch[rt[r]][1]){
    	int cur = rt[r] ;
    	rt[r] = ch[rt[r]][0] ;
    	fa[rt[r]] = 0 ;
    	clear(cur) ;
    	return ;
  	}
	int cur = rt[r] ,f = pre(r) ;
	fa[ch[cur][1]] = f ;
	ch[f][1] = ch[cur][1] ;
	clear(cur) ;
	maintain(rt[r]) ;
}

inline void ins(int &r , int x , int f){//插入节点 
	if(!r){
		r = x ;
		fa[r] = f ;
		val[r] = w[r] ;
		siz[r] = 1 ;
		return ;
	}
	pushdown(r) ;
	if(!ch[r][0])	ins(ch[r][0] , x , r) ;//此题中的val表示为最大值,同一棵树的val相同。 
	else ins(ch[r][1] , x , r) ;
}

map<pii , int> vis ;
int num ;

int main(){
	int n ;scanf("%d" , &n) ;
	for(int i = 1;i <= n;++i){
		int x ,y ;scanf("%d%d%d"  , w+i , &x , &y) ;
		if(!vis.count(make_pair(x , y)))	vis[make_pair(x , y)] = ++num ;
		int k = vis[make_pair(x , y)] ;
		a[i] = k ;
		ans1[i] = max(ans1[i] , val[rt[k]]) ;
		ans2[i] = max(ans2[i] , siz[rt[k]]) ;
		ins(rt[k] , i , 0) ;
		rt[k] = splay(i) ;
		wlazy[rt[k]] = max(wlazy[rt[k]] , w[i]) ;
        slazy[rt[k]] = max(slazy[rt[k]] , siz[rt[k]]-1) ;
	}
	int t ;scanf("%d" , &t) ;
	while(t--){
		int id ,x ,y ;
        scanf("%d%d%d" , &id , &x , &y) ;
        if(!vis.count(make_pair(x , y))){
            vis[make_pair(x , y)] = ++num ;
        }
        int k = vis[make_pair(x , y)] ,pre = a[id] ;
        a[id] = k ;
        del(pre , id) ;
        ans1[id] = max(ans1[id] , val[rt[k]]) ;
        ans2[id] = max(ans2[id] , siz[rt[k]]) ;
        ins(rt[k] , id , 0) ;
        rt[k] = splay(id) ;
        wlazy[rt[k]] = max(wlazy[rt[k]] , w[id]) ;
        slazy[rt[k]] = max(slazy[rt[k]] , siz[rt[k]]-1) ;
	}
	for(int i = 1;i <= n;++i){
		rt[a[i]] = splay(i) ;
		printf("%lld\n" , 1ll * ans1[i] * ans2[i]) ;
	}
	return 0 ;
}
posted @   adolf_stalin  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示