2827: 千山鸟飞绝 splay打标记
Description
话说有一天doyouloveme和vfleaking到山里玩。谁知doyouloveme刚刚进山,所有的鸟儿竟被他的神犇气场给惊得全部飞走了。vfleaking顿时膜拜不已。
这时鸟王用鸟语说道:“!@#$%……?”安抚了一下众鸟的情绪。鸟王生性好斗,作出了一个决定——要排鸟布阵把刚才吓到它们的人类赶出山去。
每只鸟都有一个编号,都有一个威武值。每秒钟鸟王都会发一个命令,编号为v的鸟飞到(x,y)去(坐标系原点是山顶,坐标单位为鸟爪)。鸟飞得很快,一秒之内就飞到了,可以看作是瞬间移动。如果编号为v的鸟和编号为u的鸟某一时刻处在同一位置,它们就会互相鼓励,增加各自的士气值和团结值。一只鸟的士气值等于此刻与它处在同一位置的鸟中的威武值的最大值,团结值等于此刻与它处在同一位置的鸟的只数。如果每一时刻都没有鸟与它处在同一位置,则士气值和团结值都为0。要注意自己不能鼓励自己,计算士气值和团结值时不能算上自己。
t秒钟后,doyouloveme目测出了现在每只鸟的战斗力,于是感叹了一句:“不妙,我们得走了。”
正所谓团结的鸟儿一个顶俩,所以doyouloveme这样描述战斗力:一只鸟战斗力值等于它在0到t秒中士气值的最大值与团结值的最大值的乘积。注意不是乘积的最大值,而是最大值的乘积。
vfleaking很想知道现在每只鸟的战斗力,但是他当然不会啦,于是他把这个任务交给了你来完成。
题解:
首先把坐标离散化,对每个坐标建一棵splay,以鸟的编号为关键字。然后要支持删除、插入、维护最大值,把一个新的点插入,它的答案就用那棵splay的最大值和大小来更新,然后用它自己的值来更新原来splay里的点,用打标记就行了。但是我遇到个问题,就是原来的标记有可能会传到新插入的点,我的解决方法是在插入点的时候把它的父亲到根的标记都下传,很慢,但我没想到更好的方法了……
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=30010;
const int Maxt=300010;
const int inf=2147483647;
int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();return x*f;
}
map<pa,int>h;int cnt=0;
int to(int x,int y)
{if(!h[make_pair(x,y)])h[make_pair(x,y)]=++cnt;return h[make_pair(x,y)];
}
int n,T;
struct bird{int w,x,y;}a[Maxn];
int tot=0;
int fa[Maxn+Maxt],son[Maxn+Maxt][2],root[Maxn+Maxt],size[Maxn+Maxt];
int mx[Maxn+Maxt],v[Maxn+Maxt],d[Maxn+Maxt],t1[Maxn+Maxt],t2[Maxn+Maxt];
int ans1[Maxn],ans2[Maxn];
int pos[Maxn];
void up(int x)
{if(!x)return;int lc=son[x][0],rc=son[x][1];size[x]=size[lc]+size[rc]+1;mx[x]=max(d[x],max(mx[lc],mx[rc]));
}
void down(int x)
{int lc=son[x][0],rc=son[x][1];if(t1[x]){if(lc)t1[lc]=max(t1[lc],t1[x]),ans1[v[lc]]=max(ans1[v[lc]],t1[x]);if(rc)t1[rc]=max(t1[rc],t1[x]),ans1[v[rc]]=max(ans1[v[rc]],t1[x]);t1[x]=0;}if(t2[x]){if(lc)t2[lc]=max(t2[lc],t2[x]),ans2[v[lc]]=max(ans2[v[lc]],t2[x]);if(rc)t2[rc]=max(t2[rc],t2[x]),ans2[v[rc]]=max(ans2[v[rc]],t2[x]);t2[x]=0;}
}
void rotate(int x)
{int y=fa[x],z=fa[y],w=(son[y][0]==x);son[y][w^1]=son[x][w];if(son[x][w])fa[son[x][w]]=y;son[z][son[z][1]==y]=x;fa[x]=z;son[x][w]=y;fa[y]=x;up(y);up(x);
}
int sta[Maxn+Maxt];
void work(int o,int x)
{int top=0;while(x)sta[++top]=x,x=fa[x];while(top)down(sta[top--]);
}
void splay(int o,int x,int rt)
{work(o,x);while(fa[x]!=rt){int y=fa[x],z=fa[y];if(z==rt)rotate(x);else rotate(((son[z][0]==y)==(son[y][0]==x))?y:x),rotate(x);}if(!rt)root[o]=x;
}
int Find(int o,int x)
{int now=root[o];while(v[now]!=x){if(!son[now][x>v[now]])break;now=son[now][x>v[now]];}return now;
}
void add(int o,int x,int y,int f)
{int t=++tot;v[t]=x;d[t]=mx[t]=y;fa[t]=f;size[t]=1;if(!f)return;work(o,f);son[f][x>v[f]]=t;up(f);splay(o,f,0);
}
void ins(int o,int x,int y)
{if(!root[o]){root[o]=tot+1;add(o,x,y,0);return;}add(o,x,y,Find(o,x));
}
void Insert(int o,int x,int y)
{int t=root[o];if(!t){ins(o,x,y);return;}ans1[x]=max(ans1[x],mx[t]);ans2[x]=max(ans2[x],size[t]);ins(o,x,y);t=tot;splay(o,t,0);t1[t]=max(t1[t],y);t2[t]=max(t2[t],size[t]-1);
}
void del(int x)
{int o=pos[x],t=Find(o,x);splay(o,t,0);if(size[t]==1){root[o]=0;return;}int lc=son[t][0],rc=son[t][1];if(lc&&!rc){root[o]=lc;fa[lc]=0;return;}if(!lc&&rc){root[o]=rc;fa[rc]=0;return;}if(!son[t][0]){root[o]=rc;fa[rc]=0;return;}int p=son[t][0];while(son[p][1])p=son[p][1];splay(o,p,t);root[o]=p;fa[p]=0;son[p][1]=son[t][1];if(son[t][1])fa[son[t][1]]=p;up(p);
}
void dfs(int x)
{if(!x)return;down(x);dfs(son[x][0]);dfs(son[x][1]);
}
int main()
{n=read();for(int i=1;i<=n;i++){a[i].w=read(),a[i].x=read(),a[i].y=read();int t=to(a[i].x,a[i].y);Insert(t,i,a[i].w);pos[i]=t;}T=read();while(T--){int i=read(),x=read(),y=read();del(i);pos[i]=to(x,y);Insert(pos[i],i,a[i].w);}for(int i=1;i<=cnt;i++)if(root[i])dfs(root[i]);for(int i=1;i<=n;i++)printf("%lld\n",(LL)(ans1[i])*(LL)(ans2[i]));
}
2827: 千山鸟飞绝 splay打标记相关推荐
- CODEVS-1082-线段树练习3-splay
描述 区间修改, 区间求和 分析 想练练splay打标记. 因为splay不支持永久标号, 所以pushdown后必须把标记清掉. 第一次打上标记后要立刻让标记生效. 需要注意的地方是pushdown ...
- 简析平衡树(三)——浅谈Splay
前言 原本以为\(Treap\)已经很难了,学习了\(Splay\),我才知道,没有最难,只有更难.(强烈建议先去学一学\(Treap\)再来看这篇博客) 简介 \(Splay\)是平衡树中的一种,除 ...
- [BZOJ1503]郁闷的出纳员(Splay)
Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常 ...
- Splay ---- 2018牛客多校第三场 区间翻转搞区间位移 或者 rope可持久化块状链表
题目链接 题目大意: 就是每次把牌堆中若干个连续的牌放到堆顶,问你最后牌的序列. 解题思路: Splay 区间翻转的模板题: 对于一个区间[1,2,3,4,5,6,7,8][1,2,3,4,5,6,7 ...
- Splay ---- 区间翻转 区间最大值 区间加 P4146 序列终结者
题目链接 题目大意: 解题思路: 这是一道很入门的Splay的题目 但是第一次写有很多坑点 首先是maxmaxmax值的更新:就是因为这个点的最小值是会出现负数负数的,当你左右儿子有一个没有的话,那么 ...
- Splay ---- 文艺平衡树区间翻转的建树模式
Splay 的区间操作 这个splay已经不是平常的权值splay了, 每个节点维护区间的位置取决于它在树里面的位置 首先这课splay中序遍历的结果就是你维护的整个区间的数值!!注意这个中序遍历很重 ...
- 三大平衡树(Treap + Splay + SBT)总结+模板
Treap树 核心是 利用随机数的二叉排序树的各种操作复杂度平均为O(lgn) Treap模板: #include <cstdio> #include <cstring> #i ...
- bzoj3786星系探索 splay
3786: 星系探索 Time Limit: 40 Sec Memory Limit: 256 MB Submit: 1314 Solved: 425 [Submit][Status][Discu ...
- UVA_11922 Permutation Transformer 【splay树】
一.题目 UVA11922 二.分析 为什么会有伸展树? 伸展树与AVL的区别除了保持平衡的方式不同外,最重要的是在每次查找点时,让该点旋转到根结点,这里可以结合计算机里的局部性原理思考. 伸展树有什 ...
最新文章
- java大文件读写操作
- Python 之 Numpy (二)array
- sql server 链接到oracle库,读取对应信息
- 【正一专栏】王者的尊严和荣耀
- 硬编码学习笔记(一)—— 经典定长指令
- 【星球知识卡片】换脸算法和人脸驱动都有哪些核心技术,如何对其长期深入学习...
- 【学生信息管理系统】——总结篇
- jedis对redis键加锁+解锁+事务提交
- pip is configured with locations that require TLS/SSL, however the ssl module in Python is not avail
- ajax jsonp img
- ParaView绘制gprMax正演模拟的波场快照方法(1)
- PHP依赖注入(DI)和控制反转(IOC)
- 关闭打印机 文件共享的服务器,文件和打印机共享服务可以禁止?
- Qt数据库应用3-数据打印到pdf
- 2021年高压电工模拟考试题及高压电工模拟考试题库
- 最快的Android TreeView出现了!
- 复旦大学管理学院2017年考博(高级微观经济学+管理理论综合)真题,高微老师上课资料
- 如何写系统需求分析书
- java交错数组,C#交错数组用法实例
- Android_Butterfly_动画