博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[洛谷P3203][HNOI2010]弹飞绵羊
阅读量:6099 次
发布时间:2019-06-20

本文共 2439 字,大约阅读时间需要 8 分钟。

题目大意:有$n$个节点,第$i$个节点有一个弹力系数$k_i$,当到达第$i$个点时,会弹到第$i+k_i$个节点,若没有这个节点($i+k_i>n$)就会被弹飞。有两个操作:

  1. $x:$询问从第$x$个节点开始要多少次会被弹飞
  2. $x,y:$把第$x$个点的弹力系数修改为$y$。

题解:建一个节点标号$n+1$,所有大于$n$的位置都连向这,表示会被弹飞。其他每个节点向会被弹到的节点连边($i->k_i+i$),发现这样会构成一棵树。

询问就是问该点的深度(到$n+1$的距离)。修改就是把原来的边切断,再连上一条新边。可以想到$LCT$,只需要维护每个点到链顶的距离即可。

卡点:1.$get$函数写错

    2.在$link$和$cut$操作中换了根,但是在询问中是按照根为$n+1$来做的

C++ Code:

#include 
#define maxn 200010#define lc(rt) son[rt][0]#define rc(rt) son[rt][1]using namespace std;int sz[maxn], son[maxn][2], fa[maxn], tg[maxn];inline int min(int a, int b) {return a < b ? a : b;}inline void swap(int &a, int &b) {a ^= b ^= a ^= b;}inline int get(int rt, int flag = 1) {return son[fa[rt]][flag] == rt;}inline bool is_root(int rt) {return !(get(rt, 0) || get(rt));}inline void update(int rt) {sz[rt] = sz[lc(rt)] + sz[rc(rt)] + 1;}inline void pushdown(int rt) { tg[rt] ^= 1; tg[lc(rt)] ^= 1; tg[rc(rt)] ^= 1; swap(lc(rt), rc(rt));}inline void rotate(int x) { int y = fa[x], z = fa[y], b = get(x); if (!is_root(y)) son[z][get(y)] = x; fa[son[y][b] = son[x][!b]] = y; son[x][!b] = y; fa[y] = x, fa[x] = z; update(y), update(x);}int stack[maxn], top;inline void splay(int x) { stack[top = 1] = x; for (int y = x; !is_root(y); stack[++top] = y = fa[y]); for (; top; top--) if (tg[stack[top]]) pushdown(stack[top]); for (; !is_root(x); rotate(x)) if (!is_root(fa[x])) get(x) ^ get(fa[x]) ? rotate(x) : rotate(fa[x]); update(x);}inline void access(int rt) {for (int t = 0; rt; rc(rt) = t, t = rt, rt = fa[rt]) splay(rt);}inline void make_root(int rt) {access(rt), splay(rt), tg[rt] ^= 1;}inline void link(int x, int y) {make_root(x), fa[x] = y;}inline void split(int x, int y) {make_root(x), access(y), splay(y);}inline void cut(int x, int y) {split(x, y), lc(y) = fa[x] = 0;}int n, m;inline int ask(int rt) { make_root(n + 1); access(rt); splay(rt); return sz[rt] - 1;}int s[maxn];int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &s[i]); link(i, min(n + 1, i + s[i])); } scanf("%d", &m); for (int i = 0; i < m; i++) { int op, x, y; scanf("%d%d", &op, &x); x++; if (op == 1) printf("%d\n", ask(x)); else { scanf("%d", &y); cut(x, min(n + 1, x + s[x])); s[x] = y; link(x, min(n + 1, x + y)); } } return 0;}

 

转载于:https://www.cnblogs.com/Memory-of-winter/p/9526749.html

你可能感兴趣的文章
Tomcat与Spring中的事件机制详解
查看>>
Spark综合使用及用户行为案例区域内热门商品统计分析实战-Spark商业应用实战...
查看>>
初学者自学前端须知
查看>>
Retrofit 源码剖析-深入
查看>>
企业级负载平衡简介(转)
查看>>
ICCV2017 论文浏览记录
查看>>
科技巨头的交通争夺战
查看>>
当中兴安卓手机遇上农行音频通用K宝 -- 卡在“正在通讯”,一直加载中
查看>>
Shell基础之-正则表达式
查看>>
JavaScript异步之Generator、async、await
查看>>
讲讲吸顶效果与react-sticky
查看>>
c++面向对象的一些问题1 0
查看>>
直播视频流技术名词
查看>>
iOS13-适配夜间模式/深色外观(Dark Mode)
查看>>
网易跟贴这么火,背后的某个力量不可忽视
查看>>
企业级java springboot b2bc商城系统开源源码二次开发-hystrix参数详解(八)
查看>>
java B2B2C 多租户电子商城系统- 整合企业架构的技术点
查看>>
IOC —— AOP
查看>>
比特币现金将出新招,推动比特币现金使用
查看>>
数据库的这些性能优化,你做了吗?
查看>>