bzoj2827: 千山鸟飞绝 treap

离散化坐标,每个坐标开一棵以鸟的编号为关键字的平衡树。每次插入时打2个标记,同时更新自身。这个方法比较显然,而且好写。正解好像用很迷的方法乱搞了一波,然后用线段树不打标记就做出来了,并不会。

treap旋转没传引用,调了好久。

#include<bits/stdc++.h>
#define N 30005
#define M 330005
#define x first
#define y second
#define IF else if
using namespace std;
int n,m,i,v[M];
typedef int ds[N];
ds f,l,r,z;
typedef pair<int,int> vec;
vec a[M],s[M];
struct node{
	int v,a,i,j,s,q;
	node *r,*l;
}*t[M],e[M];
node* back=e+1;
node* null=e;
node* create(int v){
	return &(*back++
	=(node){v,z[v],
	0,0,1,rand(),e,e});
}
void update(node* t){
	t->s=t->l->s
	+t->r->s+1;
	t->a=max(max(
	t->l->a,
	t->r->a),z[t->v]);
}
void lturn(node*& t){
	node* s=t->r;
	t->r=s->l;
	update(s->l=t);
	update(t=s);
}
void rturn(node*& t){
	node* s=t->l;
	t->l=s->r;
	update(s->r=t);
	update(t=s);
}
void eq2(int& a,int b){
	a=a<b?b:a;
}
void devolve(node* s){
	eq2(s->l->i,s->i);
	eq2(s->l->j,s->j);
	eq2(s->r->i,s->i);
	eq2(s->r->j,s->j);
	eq2(l[s->v],s->i);
	eq2(r[s->v],s->j);
	s->i=s->j=0;
}
void insert(int v,
node*& s){
	if(s==null)
		s=create(v);
	devolve(s);
	if(v<s->v){
		insert(v,s->l);
		if(s->l->q>s->q)
			rturn(s);
	}IF(s->v<v){
		insert(v,s->r);
		if(s->r->q>s->q)
			lturn(s);
	}
	update(s);
}
void erase(int v,
node*& s){
	devolve(s);
	if(v<s->v)
		erase(v,s->l);
	IF(s->v<v)
		erase(v,s->r);
	IF(s->l==null){
		s=s->r;
		return;
	}IF(s->r==null){
		s=s->l;
		return;
	}IF(s->l->q>s->r->q){
		devolve(s->l);
		rturn(s);
		erase(v,s->r);
	}else{
		devolve(s->r);
		lturn(s);
		erase(v,s->l);
	}
	update(s);
}
void come(int v,
node*& s){
	eq2(s->i,z[v]);
	eq2(s->j,s->s);
	eq2(l[v],s->a);
	eq2(r[v],s->s);
	insert(v,s);
}
void dfs(node* t){
	if(t!=null){
		devolve(t);
		dfs(t->l);
		dfs(t->r);
	}
}
int main(){
	srand(20000327);
	scanf("%d",&n);
	for(i=1;i<=n;++i){
		scanf("%d%d%d",z+i,
		&a[i].x,&a[i].y);
		s[i]=a[i];
	}
	scanf("%d",&m);
	for(i=n+1;i<=n+m;++i){
		scanf("%d%d%d",v+i,
		&a[i].x,&a[i].y);
		s[i]=a[i];
	}
	sort(s+1,s+n+m+1);
	for(i=1;i<=n+m;++i)
		t[i]=null;
	for(i=1;i<=n;++i)
		come(i,t[f[i]
		=lower_bound(
		s+1,s+n+m+1,a[i])-s]);
	for(i=n+1;i<=n+m;++i){
		erase(v[i],
		t[f[v[i]]]);
		come(v[i],t[f[v[i]]
		=lower_bound(
		s+1,s+n+m+1,a[i])-s]);
	}
	for(i=1;i<=n;++i){
		dfs(t[f[i]]);
		t[f[i]]=null;
		printf("%lld"
		"\n",1ll*l[i]*r[i]);
	}
}

  

时间: 2024-12-21 06:42:03

bzoj2827: 千山鸟飞绝 treap的相关文章

bzoj2827: 千山鸟飞绝

Description 话说有一天doyouloveme和vfleaking到山里玩.谁知doyouloveme刚刚进山,所有的鸟儿竟被他的神犇气场给惊得全部飞走了.vfleaking顿时膜拜不已. 这时鸟王用鸟语说道:“[email protected]#$%……?”安抚了一下众鸟的情绪.鸟王生性好斗,作出了一个决定——要排鸟布阵把刚才吓到它们的人类赶出山去. 每只鸟都有一个编号,都有一个威武值.每秒钟鸟王都会发一个命令,编号为v的鸟飞到(x,y)去(坐标系原点是山顶,坐标单位为鸟爪).鸟飞得

2827: 千山鸟飞绝 非旋treap

国际惯例的题面:看起来很不可做的样子,我们先来整理一下题意吧.就是,维护每个点曾经拥有过的最大的两个属性值,支持把点的位置移动.我们用map对每个位置进行离散化,对每个位置建立一个平衡树.为了方便分离,这个平衡树的关键字是节点编号.然后把每个点当做一个节点,放进其所在位置的平衡树里.剩下要做的就是平衡树分离出一个点,合并一个点,还有打标记了.对于士气值的标记,我们维护平衡树中的max,每次合并的时候,用这个新点的威武值去给整棵树打标记,再用树中的max给这个新点打标记.团结值的标记,合并后一起打

【BZOJ2827】千山鸟飞绝 离散化+splay

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45721413"); } 题解: 首先先把坐标离散化一下, 然后对于每个坐标点我们建一棵平衡树,每次插入操作后给整颗平衡树下传一下需求的两个标记. 注意: splay有的人(比如我)习惯每棵都先建-inf.inf两个节点以便于查找前驱

[POI2008] Poc (原名 Trians) Treap+Hash

这个题和千山鸟飞绝体现出了一种用平衡树解决动态集合问题,主要套路就是蜜汁标记. 这个题我一开始用替罪羊树搞了一下对了28个点,后来我换成了Treap一搞对了14个点,再后来发现被卡了Hash我竟然在自然溢出中用了256.... 上代码 #include<cstdio> #include<cstring> #include<map> #include<cstdlib> #define N 1010 #define L 110 #define M 100010

Treap

先推荐一篇文章和黄学长的代码http://hzwer.com/1712.html    https://wenku.baidu.com/view/c8c11e1e650e52ea55189887.html 黄学长的代码既不用指针又很短,真心推荐 Treap,顾名思义,Tree+Heap,它既满足二叉搜索树的性质,又满足堆的性质 对于二叉搜索树,如果我们把数有序加入,那么它的时间效率会退化成O(n). 我们引入一个随机数(即下文描述的修正值),使得随机数满足堆的性质(小根堆或大根堆,不一定要是完全

【贪心+Treap】BZOJ1691-[Usaco2007 Dec]挑剔的美食家

[题目大意] 有n头奶牛m种牧草,每种牧草有它的价格和鲜嫩度.每头奶牛要求它的牧草的鲜嫩度要不低于一个值,价格也不低于一个值.每种牧草只会被一头牛选择.问最少要多少钱? [思路] 显然的贪心,把奶牛和牧草都按照鲜嫩度由大到小排序,对于每奶牛把鲜嫩度大于它的都扔进treap,然后找出后继. 不过注意后继的概念是大于它且最小的,然而我们这里是可以等于的,所以应该是找cow[i].fresh-1的后继,注意一下…… 1 #include<iostream> 2 #include<cstdio&

1503: [NOI2004]郁闷的出纳员 Treap

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 6263  Solved: 2190[Submit][Status] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可

数组splay ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) #include <cstdio> #define Max 100005 #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (int &now) { now = 0; register char word = getchar (); bool temp = false; while (wor

平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】

平衡树初阶——AVL平衡二叉查找树 一.什么是二叉树 1. 什么是树. 计算机科学里面的树本质是一个树状图.树首先是一个有向无环图,由根节点指向子结点.但是不严格的说,我们也研究无向树.所谓无向树就是将有向树的所有边看成无向边形成的树状图.树是一种递归的数据结构,所以我们研究树也是按照递归的方式去研究的. 2.什么是二叉树. 我们给出二叉树的递归定义如下: (1)空树是一个二叉树. (2)单个节点是一个二叉树. (3)如果一棵树中,以它的左右子节点为根形成的子树都是二叉树,那么这棵树本身也是二叉