【HDU4010】【LCT】Query on The Trees
There
are N nodes, each node will have a unique weight Wi. We
will have four kinds of operations on it and you should solve them
efficiently. Wish you have fun!
For
each case, the first line contains only one integer N.(1 ≤ N ≤
300000) The next N‐1 lines each contains two integers x, y which means
there is an edge between them. It also means we will give you one tree
initially.
The next line will contains N integers which means the weight Wi of each node. (0 ≤ Wi ≤ 3000)
The
next line will contains an integer Q. (1 ≤ Q ≤ 300000) The next Q
lines will start with an integer 1, 2, 3 or 4 means the kind of this
operation.
1. Given two integer x, y, you should make a new edge
between these two node x and y. So after this operation, two trees will
be connected to a new one.
2. Given two integer x, y, you should
find the tree in the tree set who contain node x, and you should make
the node x be the root of this tree, and then you should cut the edge
between node y and its parent. So after this operation, a tree will be
separate into two parts.
3. Given three integer w, x, y, for the x, y and all nodes between the path from x to y, you should increase their weight by w.
4.
Given two integer x, y, you should check the node weights on the path
between x and y, and you should output the maximum weight on it.
each query you should output the correct answer of it. If you find this
query is an illegal operation, you should output ‐1.
You should output a blank line after each test case.
1 2
2 4
2 5
1 3
1 2 3 4 5
6
4 2 3
2 1 2
4 2 3
1 3 5
3 2 1 4
4 1 4
-1
7
We define the illegal situation of different operations:
In first operation: if node x and y belong to a same tree, we think it's illegal.
In second operation: if x = y or x and y not belong to a same tree, we think it's illegal.
In third operation: if x and y not belong to a same tree, we think it's illegal.
In fourth operation: if x and y not belong to a same tree, we think it's illegal.
/*
唐代白居易
《浪淘沙·借问江潮与海水》
借问江潮与海水,何似君情与妾心?
相恨不如潮有信,相思始觉海非深。
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <iomanip>
#include <string>
#include <cmath>
#include <queue>
#include <assert.h>
#include <map>
#include <ctime>
#include <cstdlib>
#include <stack>
#define LOCAL
const int INF = 0x7fffffff;
const int MAXN = + ;
const int maxnode = ;
const int maxm= * + ;
using namespace std; struct Link_Cut_Tree{
struct Node{//splay节点
int val, add;
int Max, turn;
Node *parent, *ch[];
}node[MAXN], *null;
Node *pos;//计数
Node *tmp[MAXN]; void change(Node *u){access(u)->turn ^= ;}//注意因为x是在右子树要翻转
void init(){
//循环指针
null = node;
null->parent = null->ch[] = null->ch[] = null;
null->Max = null->val = -INF;
null->add = null->turn = ; pos = node + ;
}
//用这种方法实现快捷方便.便于直接查找
Node *NEW(int x){
pos->Max = pos->val = x;
pos->turn = pos->add = ;
pos->parent = pos->ch[] = pos->ch[] = null;
return pos++;
}
//判断x是否是根,注意这个是判断是否是splay的根,而不是lct的根
bool is_root(Node *x){
if (x == null || (x->parent->ch[] != x && x->parent->ch[] != x)) return ;
return ;
}
//标记下传
void pushdown(Node *x){
if (x == null) return;
if (x->turn){//翻转标记 if (x->ch[] != null) x->ch[]->turn ^= ;
if (x->ch[] != null) x->ch[]->turn ^= ;
swap(x->ch[], x->ch[]);//交换左右子树.
x->turn = ;
}
//权值标记
if (x->add){
if (x->ch[] != null){
x->ch[]->val += x->add;
x->ch[]->Max += x->add;
x->ch[]->add += x->add;
}
if (x->ch[] != null){
x->ch[]->val += x->add;
x->ch[]->Max += x->add;
x->ch[]->add += x->add;
}
x->add = ;
}
return;
}
//更新
void update(Node *x){
if (x == null) return;
x->Max = max(x->val, max(x->ch[]->Max, x->ch[]->Max));
} //d = 0为左旋,否则为右旋
void rotate(Node *x, int d){
if (is_root(x)) return;//是根就不转
Node *y = x->parent;
y->ch[d ^ ] = x->ch[d];
if (x->ch[d] != null) x->ch[d]->parent = y;
x->parent = y->parent;
if (y != null){
if (y == y->parent->ch[]) y->parent->ch[] = x;
else if (y == y->parent->ch[]) y->parent->ch[] = x;
}
x->ch[d] = y;
y->parent = x;
update(y);
}
//将x转到根
void splay(Node *x){
//带标记splay的伸展操作
//将从顶部到根部的节点全部pushdown
int cnt = ;
tmp[] = x;
for (Node *y = x; !is_root(y); y = y->parent) tmp[cnt++] = y->parent;
while (cnt) pushdown(tmp[--cnt]); while (!is_root(x)){
Node *y = x->parent;
if (is_root(y)) rotate(x, (x == y->ch[]));
else {
int d = (y->parent->ch[] == y);
if (y->ch[d] == x) rotate(x, d ^ );
else rotate(y, d);
rotate(x, d);
}
}
update(x);
}
//lct的访问操作,也是核心代码
Node *access(Node *u){
Node *v = null;
while (u != null){//非lct根,总是放在右边
splay(u);
v->parent = u;
u->ch[] = v;
update(u);
v = u;
u = u->parent;
}
return v;
}
//合并操作
void merge(Node *u, Node *v){
//if (u->val == 2 && v->val == 5)
//printf("%d\n", u->ch[0]->val);
//注意u为根
access(u);
splay(u); u->turn = ;//翻转,因为在access之后,u已经成为splay中深度最大的点,因此右子树为null,此时要成为根就要翻转
u->parent = v;
}
void cut(Node *u){
access(u);
splay(u);
//注意到u为根,自然深度最小,分离出来
u->ch[]->parent = null;
u->ch[] = null;
update(u);
}
//找根,不是真根
Node *findroot(Node *u){
access(u);//不仅要打通,而且要让u成为根
splay(u); while (u->parent != null) u = u->parent;
return u;
}
//判断u和v是否在同一个子树中
bool check(Node *u, Node *v){
while (u->parent != null) u = u->parent;
while (v->parent != null) v = v->parent;
return (u == v);
}
}splay;
int u[MAXN],v[MAXN];
int n, m;
/*struct Node{
Node *ch[2];
int val;
};
Node* rotate(Node *t, int d){
Node *p = t->ch[d ^ 1];
t->ch[d ^ 1] = p->ch[d];
p->ch[d] = t;
t = p;
return t;
}*/
void init(){
splay.init();
for (int i = ; i < n; i++) scanf("%d%d", &u[i], &v[i]);
//各点权值
for (int i = ; i <= n; i++){
int t;
scanf("%d", &t);
splay.NEW(t);
}
for (int i = ; i < n; i++) {
// if (i == 3)
// printf("");
splay.merge(splay.node + u[i], splay.node + v[i]);
//printf("%d\n", splay.node[2].ch[0]->val);
}
//printf("%d", splay.check(splay.node + 4, splay.node + 5));
}
void work(){
scanf("%d", &m);
for (int i = ; i <= m; i++){
int t;
scanf("%d", &t);
if (t == ){//连接两点
int u, v;
scanf("%d%d", &u, &v);
//判断是否在同一个lct树内
if (splay.check(splay.node + u, splay.node + v)){
//printf("%d ", i);
printf("-1\n");
continue;
}
splay.merge(splay.node + u, splay.node + v);
}else if (t == ){
int u, v;
scanf("%d%d", &u, &v);
//分离两颗树
if (u == v || !splay.check(splay.node + u, splay.node + v)){
//printf("%d ", i);
printf("-1\n");
continue;
}
//转根再分离
splay.change(splay.node + u);//注意这个根是原树的根不是lct的根
splay.cut(splay.node + v);
}else if (t == ){
int u, v, w;
scanf("%d%d%d", &w, &u, &v);
//不再同一个树内自然无法更新
if (!splay.check(splay.node + u, splay.node + v)){
//printf("%d ", i);
printf("-1\n");
continue;
}
splay.change(splay.node + u);
splay.access(splay.node + v);
//将u换为真根,则u所在的splay都是v-u路径上的节点
Link_Cut_Tree::Node *q = splay.findroot(splay.node + v);
q->add += w;
q->Max += w;
q->val += w;
}else {//查询操作
int u, v;
scanf("%d%d", &u, &v);
if (!splay.check(splay.node + u, splay.node + v)){
//printf("%d ", i);
printf("-1\n");
continue;
}
//先换根
splay.change(splay.node + u);
splay.access(splay.node + v);
printf("%d\n", splay.findroot(splay.node + v)->Max);
}
}
printf("\n");
} int main (){ //scanf("%d", &n);
while (scanf("%d", &n) != EOF){
init();
work();
}
return ;
}
【HDU4010】【LCT】Query on The Trees的更多相关文章
- BZOJ2157 旅游 【树剖 或 LCT】
题目 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径. ...
- bzoj 4817: [Sdoi2017]树点涂色【树链剖分+LCT】
非常妙的一道题. 首先对于操作一"把点x到根节点的路径上所有的点染上一种没有用过的新颜色",长得是不是有点像LCT中的access操作?进而发现,如果把同一颜色的点连起来作为LCT ...
- 【UOJ274】【清华集训2016】温暖会指引我们前行 LCT
[UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很 ...
- 【Spring Data 系列学习】Spring Data JPA @Query 注解查询
[Spring Data 系列学习]Spring Data JPA @Query 注解查询 前面的章节讲述了 Spring Data Jpa 通过声明式对数据库进行操作,上手速度快简单易操作.但同时 ...
- 【BZOJ3669】【Noi2014】魔法森林(Link-Cut Tree)
[BZOJ3669][Noi2014]魔法森林(Link-Cut Tree) 题面 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n ...
- 【原创分享·微信支付】 C# MVC 微信支付教程系列之扫码支付
微信支付教程系列之扫码支付 今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添 ...
- 【AutoMapper官方文档】DTO与Domin Model相互转换(中)
写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...
- 【SQL篇章--DATABASE/EVENTS】
[SQL篇章][SQL语句梳理 :--基于MySQL5.6][已梳理:DATABASE/EVENTS][会坚持完善] 目录: 1. Data Definition Statements: 1.1 ...
- 【ipv6惹的祸】curl 超时
偶然发现 最近在公司日志平台 总是可以看到很多关于php curl的错误信息 Operation timed out after 0 milliseconds with 0 out of 0 byte ...
- 最全的MySQL基础【燕十八传世】
1.课前准备! 开启mysql服务:1).配置环境变量;2).net start mysql 将该sql文件导入到你的数据库中,以下所有操作都是基于该数据库表操作的!!! [此笔记是本人看着视频加上自 ...
随机推荐
- iso学习网站记录
[零基础学习iOS开发] http://www.cnblogs.com/mjios/archive/2013/04/24/3039357.html 非零基础学习iOS开发2-Objective-C h ...
- Google Map API 学习四
- jQuery 数据 DOM 元素 核心 属性
jQuery 参考手册 - 数据 .clearQueue() 从序列中删除仍未运行的所有项目 .clearQueue(queueName) $("div").clearQueue( ...
- openStack使用宿主机监控
10个vm 平稳运行 top 数值
- C#在ASP.NET4.5框架下的首次网页应用
运行效果预览: 先看实践应用要求: 1.编写一个函数,用于计算1!+2!+3!+4!+5!,在控制台或页面输出运行结果. 2.在控制台或页面输出九九乘法表. 3.输入10个以内的整数,输出该组整数的降 ...
- hdu 1242 dfs/bfs
Problem Description Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is ...
- kafka offset-check工具失效的问题
转载请注明原创地址http://www.cnblogs.com/dongxiao-yang/p/5414077.html 由于平时业务预警等需求,针对现在公司的kafka系统部署了几套监控系统,包括调 ...
- 无需Cygwin,如果没有在命令行,Eclipse编NDK
此链接 http://blog.csdn.net/xiaodongrush/article/details/28908829 參考链接 http://www.cnblogs.com/che ...
- Androidannotation使用之@Rest与server交互的JSON数据转换(二)
开篇 之前的一篇博客:Androidannotation使用之@Rest获取资源及用户登录验证(一):http://blog.csdn.net/nupt123456789/article/detail ...
- Java基础知识强化09:String、StringBuffer和StringBuilder使用
1. 对于三者使用的总结: (1).如果要操作少量的数据用 = String (2).单线程操作字符串缓冲区下操作大量数据 = StringBuilder (3).多线程操 ...