首页 > 其他分享 >luogu P4200 千山鸟飞绝 题解 【一维数组套平衡树】

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

时间:2023-08-09 16:24:52浏览次数:45  
标签:rt ch cur int luogu fa MAXN 题解 山鸟飞

目录

题目

题目链接

解题思路

首先,此题有明显的插入、删除、查找,所以必须要使用平衡树。
考虑如何使用平衡树维护每个鸟的状态。发现很不方便,因为鸟的位置改变,整个平衡树的值都要修改。
考虑针对每个节点开一颗平衡树,这样就有\(3e4\times 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 ;
}

标签:rt,ch,cur,int,luogu,fa,MAXN,题解,山鸟飞
From: https://www.cnblogs.com/adolf-stalin/p/17615723.html

相关文章

  • P9507 [BalkanOI2018] Popa 题解
    原题传送门题目描述Ghiță有一个下标从\(0\)开始的正整数序列\(S\)。因为他是喀尔巴阡的国王,所以他想要构造一个节点编号为\(0,1,\ldots,N-1\)的二叉树,满足:树的中序遍历按节点编号升序排列。二叉树的中序遍历由以根的左子节点(如果存在)为根形成的子树的中序遍历,根的节......
  • 桐柏邀请赛 S15 题解
    定位:给中低段位一点压力,给中高段位一点信心!A发现只是单向变换\((0\to1)\),用两个变量维护位置最小值和最大值即可。#defineintlonglongintn,q,maxn,minn=1e18+1,x;signedmain(){ n=read(),q=read(); while(q--){ x=read(); maxn=max(maxn,x); minn=min(minn,x......
  • CF1857B Maximum Rounding 题解
    题面题目大意给定\(T\)组数据,每组数据一个自然数\(n\),可以多次选择第\(k\)位数进行四舍五入,求出四舍五入后该数的最大值。分析思路思想:贪心。这里给定了两种操作。四舍和五入。显然我们想要让最终的结果最大,我们的操作只能进行五入而不可以进行四舍。因为如果我们进行了......
  • 国标GB28181视频平台LntonGBS(源码版)国标平台级联时,通道上传上级宇视平台无法接收的问
    LntonGBS是基于公安部推出的GB/T28181协议开发的视频平台,在安防监控领域应用广泛。下面是一些关于LntonGBS平台的主要特点:GB/T28181协议兼容性、视频直播和转码、云端录像和存储、语音对讲和警告功能、平台级联功能。通过以上的功能和特点,LntonGBS平台能够满足安防监控领域各类场景......
  • sudo: a terminal is required to read the password; either use..... 问题解决方法
    转载自:sudo:aterminalisrequiredtoreadthepassword;eitheruse……问题解决方法_akaiziyou的博客-CSDN博客问题sudo:aterminalisrequiredtoreadthepassword;eitherusethe-Soptiontoreadfromstandardinorconfigureanaskpasshelper出现场景某个......
  • Codeforces Round 891 (Div. 3) 题解
    A.ArrayColoring因为:偶数+偶数=偶数奇数+奇数=偶数奇数+偶数=奇数所以设\(s1\)为奇数之和,\(s2\)为偶数之和\(s2\)必定是偶数如果奇数的个数为偶数,则\(s1\)为偶数;否则是奇数而在\(s1\)为奇数时,即使拿一个奇数加到\(s2\)里,那么也是不合法的所以直接判断奇数的......
  • CF1477E题解
    洛谷博客链接此篇未投洛谷题解,因为写得太菜了qwq。CF1477E&大户爱的送分题题解(CF1477E为我出的校内模拟赛的一道题——《大户爱的送分题》的待修版本)大户爱的送分题文件名OhtoAiFirst.cpp/.in/.out,时间限制\(1\)秒,空间限制\(256MB\)。注意第一个字母是O而不是0。题目背......
  • CF1030F题解
    CF1030F题解传送门 更好的阅读体验简化题意:有$n$个小球,每个小球在位置$a_i$,移动一格的代价是$w_i$,有两种操作,一种是将$w_x$改成$y$,一种是查询$\min\limits_{x=1}^n\{\sum\limits_{i=l}^rw_i\times(|a_x-a_i|+|x-i|)\}$。思路很好的线段树二分练手题。对于每......
  • CF1239E 题解
    CF1239E给定\(2n\)个数,将其重排成\(2\timesn\)的矩阵,最小化:从\((1,1)\)走到\((2,n)\),只可向右下走的所有方案中,途径所有数的和的最大值。\(n\le25,|V|\le5\times10^4\)。考场上有个\(n\le10\)的包,分值高达\(40\)。注意到\(\binom{20}{10}\approx10^5\)可枚......
  • 2023年 8月7日普及组南外集训题解
    A国家集训队题解注意数据已经是有序的,我还搞了个排序,我是智障所以只需要将第5个人到第16个人的成绩都预设成300,再把前4个人的成绩都预设成0,再看有没有人能超过第4个人就行了ac代码#include<iostream>usingnamespacestd;constintN=20;inta[N],ans=4;intmain(......