【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文件导入到你的数据库中,以下所有操作都是基于该数据库表操作的!!! [此笔记是本人看着视频加上自 ...
随机推荐
- 了解 Windows Azure 存储计费 – 带宽、事务和容量
我们收到关于如何估算 Windows Azure存储成本,以便了解如何更好地构建一个经济有效的应用程序的问题.在本文中,我们将从带宽.事务和容量这三种存储成本的角度探讨这一问题. 使用 Wind ...
- 【转】android: 长按删除listview的item
原文网址:http://www.cnblogs.com/nuistlr/archive/2012/09/07/2675649.html 首先要继承OnItemLongClickListener pub ...
- 265行JavaScript代码的第一人称3D H5游戏Demo【个人总结1】
本文目的是分解前面的代码.其实,它得逻辑很清楚,只是对于我这种只是用过 Canvas 画线(用过 Fabric.js Canvas库)的人来说,这个还是很复杂的.我研究这个背景天空也是搞了一天,下面就 ...
- Hibernate(十一)多对多双向关联映射
上次我们在中Hibernate从入门到精通(十)多对多单向关联映射讲解了一下多对多单向关联映射,这次我 们讲解一下七种映射中的最后一种多对多双向关联映射. 多对多双向关联映射 按照我们之前的惯例,先看 ...
- Hibernate(二)Hibernate 实例
上篇Hibernate(一)JDBC简介,我们主要对JDBC进行了简单介绍和使用说明,这次我们做一个Hibernate简单实例,通过这个实例对比Hibernate和JDBC,了解Hibernate的优 ...
- ACM1019_最大公倍数
/*问题说明 一组正整数的最小公倍数(LCM)是最小的正整数约数集合中的所有号码. 例如,5,7和15的最小公倍数是105. 输入 输入将包括多个问题的实例.输入的第一行中,将包含一个整数, 表示问题 ...
- OpenStack Havana 部署在Ubuntu 12.04 Server 【OVS+GRE】(三)——计算节点的安装
序:OpenStack Havana 部署在Ubuntu 12.04 Server [OVS+GRE] 计算节点: 1.准备结点 安装好ubuntu 12.04 Server 64bits后,进入ro ...
- ios打包ipa的四种实用方法
总结一下,目前.app包转为.ipa包的方法有以下几种: 1.Apple推荐的方式,即实用xcode的archive功能 Xcode菜单栏->Product->Archive->三选 ...
- Tomcat8 配置NIO
conf/server.xml 打开:<Executor name="tomcatThreadPool" namePrefix="catalina-exec-&qu ...
- java如何遍历hashMap
通过Map的entrySet方法.将返回一个set集合.然后遍历这个set集合: package com.howlaa.day04; import java.util.HashMap; import ...