忧桑三角形,调了半天,真忧桑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午后坐火车赶到北京.一路上火车行驶在茫茫云海里.车窗外的世界是这样子的:一片广袤的原野 ...
随机推荐
- TextView 选择文字
final CharSequence edit = text2.getText(); text2.setCursorVisible(true); text2.setOnTouchListener(ne ...
- WinForm------如何跳转另一个窗口,同时关闭当前窗口
添加一个按钮,并为按钮添加点击事件(注:Frm_Main为需要跳转的窗口名字) private void Btn_OK_Click(object sender, EventArgs e) { //打开 ...
- Java工厂设计模式
程序在接口和子类之间加入一个过渡类,通过此过渡类端取得接口的实例化对象,一般都会称这个过渡端为工厂类 //=============================================== ...
- yourphp的eq作用
<eq name="> <span style="color:#090">是</span> <else /> 否 < ...
- C# 获取进程或线程的相关信息
信息来自: http://blog.163.com/kunkun0921@126/blog/static/169204332201293023432113/ using System; using S ...
- 固定IP 正常访问谷歌
如题 地址栏直接输入 http://173.194.1.150/ 正常使用 ~标记一下~
- oracle 11g express 修改oem端口
begin dbms_xdb.sethttpport('8081'); dbms_xdb.setftpport('0'); end; / 这样就把端口设置为8081了.
- OC-点语法
点语法的本质:方法调用 #import <Foundation/Foundation.h> #import "Person.h" int main(int argc, ...
- Think in Java(Java编程思想)-第2章 一切都是对象
1. String s = "asdf"//创建一个String引用,并初始化. String s = new String("asdf")//创建一个新对象, ...
- iOS开发 关于SEL的简单总结
SEL就是对方法的一种包装.包装的SEL类型数据它对应相应的方法地址,找到方法地址就可以调用方法.在内存中每个类的方法都存储在类对象中,每个方法都有一个与之对应的SEL类型的数据,根据一个SEL数据就 ...