忧桑三角形,调了半天,真忧桑TAT
忧桑三角形
试题描述
小J是一名文化课选手,他十分喜欢做题,尤其是裸题。有一棵树,树上每个点都有点权,现在有以下两个操作:
1. 修改某个点的点权
2. 查询点u和点v构成的简单路径上是否能选出三个点组成三角形
输入
第一行两个整数N,Q,代表点数和询问数。第二行N个整数表示点权。下面N-1行每行两个整数a,b代表a,b之间有一条边。下面Q行每行3个整数t,a,b:若t=0,询问(a,b);否则将点a的权值修改为b
输出
对于每个询问输出Y表示能构成三角形,输出N表示不能构成三角形
输入示例
输出示例
N
Y
Y
N
数据范围
对于30%的数据有N, Q ≤ 1000
对于100%的数据有N, Q ≤ 105,点权范围在32位整数范围内
Orz wzj,方法超级机智。注意到“点权范围在32位整数范围内”这句话,这是个突破口,它告诉我们a和b距离很长的时候,一定能组成一个三角形,为什么呢?我们不妨写个程序算算。
设经过的点权值序列为F,将F从大到小排序后,根据三角形三遍关系得到最好情况下Fi = Fi-1 + Fi-2(i > 2),于是可以写一个求F序列前50位的代码(为了迎合题目数据范围,我把F序列也定义为32位整型变量,下面用了一个滚动数组,F被压缩成了f1和f2):
#define maxn 51 int main() {
int f1 = , f2 = ; printf("%d %d ", f1, f2);
for(int i = ; i < maxn; i++) {
f1 += f2; printf("%d ", f1);
swap(f1, f2);
} return ;
}
(头文件自己加去吧……)
运行一下,结果如下:
- - - - -
第47个数是负数,也就是说这个F序列长度超不过47
所以算法来了:当a与b之间距离大于50时,直接输出Y,否则记录下路径所经过的节点权值然后排序处理。
如何找a与b之间的距离呢?
这里有一个思想上的易错点,你可能会想到DFS序判断祖先关系,当a是b的祖先时,说明在根节点同侧,所以用它们的深度相减,否则深度相加得到距离。乍一看思想很正确,我也因此调试半天……然而当他们的最近公共祖先(Lowest Common Ancestors,LCA)不是根节点时,第二种情况深度相加就不能得到正确距离了(想一想,为什么)。
(你不知道什么叫最近公共祖先?对于有根树T的两个结点u、v,它们的最近公共祖先是一个结点x,满足x是u、v的祖先且x的深度尽可能大。)
所以正确姿势是:只能好好写倍增算法求LCA了……
略略讲一下LCA求法。显然直接dfs是O(n)级别,会超时的,所以我们可以设fa(u, x)表示节点u的第2x级祖先,不难得到递推式:fa(u, x) = fa(fa(u, x-1), x-1)
你知道为什么要出现“第2x级祖先”吗?对于一条很长的链,我们可以把它看成一个序列,一个序列是可以分成若干个个数为2n(n∈Z+)的段的,就像一个数可以表示成二进制一样,所以一条链我们不必一个节点一个节点地走,而是可以一下跳2n个节点,而分后的序列数是log2(n)级别的,所以链上跳的步数也是log2(n)级别的。
回答询问怎么做呢?对于给定的a和b,先把它们搞到同一个深度去,不妨设a深度大于b深度,所以我们就需要用上面所讲的“跳节点”的方式把节点a跳到节点b统一深度去。接下来判断:若a和b重合了,那么显然答案就是当前的b;否则还需要再进一步寻找,让a与b同时用“跳节点”的方式向上走,直到它们的父亲(即1级祖先,fa(u, 0))相同时(注意这里为什么是父亲相同,而不是自身相同,请读者思考),那么答案就是当前结点a或b的父节点了。
怎么样?我们可以在O(logn)的时间内求出LCA了,是不是感觉棒棒哒,为自己鼓鼓掌!(- -|||)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <cstdlib>
using namespace std; int read() {
int x = , f = ; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -; c = getchar(); }
while(isdigit(c)){ x = x * + c - ''; c = getchar(); }
return x * f;
} #define maxn 200010
#define maxlog 19
#define maxm (maxn << 1)
#define LL long long
int n, q, val[maxn], m, head[maxn], next[maxm], to[maxm]; void AddEdge(int a, int b) {
to[++m] = b; next[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; next[m] = head[a]; head[a] = m;
return ;
} stack <int> S; // 人工栈需要
bool vis[maxn];
int dep[maxn], fa[maxn][maxlog], ToT;
void build(int s) { // 注意数据可能卡链式图,20万的链式图必须得老老实实写人工栈了,否则爆内存别怪我
S.push(s); // 其实谁都不想写人工栈……
while(!S.empty()) {
int u = S.top();
if(!vis[u]) {
vis[u] = ;
for(int i = ; i < maxlog; i++) if(fa[u][i-]) fa[u][i] = fa[fa[u][i-]][i-]; // 这句是求LCA预处理的核心代码
for(int e = head[u]; e; e = next[e]) if(to[e] != fa[u][]) {
dep[to[e]] = dep[u] + ; fa[to[e]][] = u;
S.push(to[e]);
}
} else S.pop();
}
return ;
} int query(int a, int b) { // 求LCA
if(dep[a] < dep[b]) swap(a, b);
for(int i = maxlog-; i >= ; i--) if(dep[a] - dep[b] >= ( << i)) a = fa[a][i]; // 先提升到同一高度
for(int i = maxlog-; i >= ; i--) if(fa[a][i] != fa[b][i]){ a = fa[a][i]; b = fa[b][i]; } // 再一起向上找祖先
return a == b ? a : fa[a][]; // a = b说明它们在同一条链上,不在一条链上时最后答案是他们的父亲(想一想,为什么)
} int path[maxn], cnt;
int main() {
n = read(); q = read();
for(int i = ; i <= n; i++) val[i] = read();
for(int i = ; i < n; i++) AddEdge(read(), read());
dep[] = ; build(n >> );
while(q--) {
int tp = read(), a = read(), b = read();
if(tp) val[a] = b;
else {
int c = query(a, b), dis = dep[a] + dep[b] - (dep[c] << ) + ;
if(dis > ){ puts("Y"); continue; }
if(dis < ){ puts("N"); continue; }
cnt = ; // 记录a到b简单路径上各边权值
while(a != c){ path[++cnt] = val[a]; a = fa[a][]; }
while(b != c){ path[++cnt] = val[b]; b = fa[b][]; }
path[++cnt] = val[c];
sort(path + , path + cnt + );
bool ok = ;
for(int i = ; i < cnt - ; i++) if((LL)path[i] + path[i+] > (LL)path[i+]) {
ok = ; break;
}
puts(ok ? "Y" : "N");
}
} return ;
}
忧桑三角形,调了半天,真忧桑TAT的更多相关文章
- 记录一个调了半天的问题:java.lang.SecurityException: Permission denied (missing INTERNET permission?)
Move the <uses-permission> elements outside of <application>. They need to be immediate ...
- NOIP练习赛题目4
肥得更高 难度级别:C: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 自2009年以来,A.B站的历史就已经步入了农业变革的黎明期.在两站的 ...
- HEOI2017 游记
你若安好,便是晴天. …… 人就像命运下的蝼蚁,谁也无法操控自己的人生. ——阮行止 …… Day 0 中午就要出发了,上午教练还搞了一场欢乐信心赛,然而还是挂惨了.T3是bzoj的原题,但是当时写的 ...
- Python3 与 C# 面向对象之~继承与多态 Python3 与 C# 面向对象之~封装 Python3 与 NetCore 基础语法对比(Function专栏) [C#]C#时间日期操作 [C#]C#中字符串的操作 [ASP.NET]NTKO插件使用常见问题 我对C#的认知。
Python3 与 C# 面向对象之-继承与多态 文章汇总:https://www.cnblogs.com/dotnetcrazy/p/9160514.html 目录: 2.继承 ¶ 2.1.单继 ...
- 一堆LCT板子
搞了一上午LCT,真是累死了-- 以前总觉得LCT高大上不好学不好打,今天打了几遍感觉还可以嘛= =反正现在的水平应付不太难的LCT题也够用了,就这样好了,接下来专心搞网络流. 话说以前一直YY不出来 ...
- [NOIP2015] 斗地主(搜索)
题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4< ...
- 天气预报API(二):全球城市、景点代码列表(“旧编码”)
说明 2016-12-10 补充 (后来)偶然发现中国天气网已经有城市ID列表的网页...还发现城市编码有两种,暂且称中国天气网这些编码为旧标准"旧编码"的特征是 9个字符长度; ...
- BZOJ-2748 音量调节 DP+背包(脑残)
水DP,一开始竟然想错了...水了半天....真可怕 2748: [HAOI2012]音量调节 Time Limit: 3 Sec Memory Limit: 128 MB Submit: 1156 ...
- BUAA & ICT 夏令营之旅
我还只有二十几岁,总应该相信点什么吧. ================================ 7.10午后坐火车赶到北京.一路上火车行驶在茫茫云海里.车窗外的世界是这样子的:一片广袤的原野 ...
随机推荐
- win 2012 关闭IE增强设置
- JavaWeb学习笔记——Ajax
- Nginx配置优化的几个参数
worker_processes 8 一般CPU(i/o)密集型配置为核数相同,网络(i/o)密集型配置为核数倍数(我配置为2倍) worker_cpu_affinity(这个没用过) 仅适用于lin ...
- mysql优化--触发器和auto_increment
1.触发器: 触发器的好处:做数据回收站或者做数据关联删除 触发器的坏处:给数据库增加压力,增删改变慢,不利与mysql移到其他数据库会出问题. 触发器建立:只能增删改,查不能建立. 例子1:创建一个 ...
- Autofac和DynamicProxy2搭配实现Aop动手训练
http://www.cnblogs.com/zhengwl/p/5433181.html Aop含义:aspect-oriented programming 实现工具介绍 Autofac是一个比较流 ...
- JSP指令
一.JSP指令简介 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分. 在JSP 2.0规范中共定义了三个指令: pa ...
- Linq_Lambda GroupBy使用笔记
今天看MVC遇到了GroupBY的Lambda表达式..有兴趣详细的看下去..得此笔记..记录之... 不罗嗦..上代码... //得到List<GroupEmail>对象 数据源 var ...
- 【转】 C++使用zlib库(-)
来自: http://blog.chinaunix.net/uid-24607609-id-2118143.html 今天看到一个gzopen函数,搜了一下他的系列函数,及相关用法 C++使 ...
- 【转】Kafka实战-Flume到Kafka
Kafka实战-Flume到Kafka Kafka 2015-07-03 08:46:24 发布 您的评价: 0.0 收藏 2收藏 1.概述 前面给大家介绍了整个Kafka ...
- Apache索引目录浏览的学习笔记
在浏览一些镜像文件站的时候,会发现网站目录是可以浏览文件(夹)列表的.举两个例子:网易开源镜像:Ubuntu.只要 Web 服务器是基于 Apache 的网站都可以开启或禁止索引(目录浏览),那么如何 ...