Description

一 棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input

输 入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数 q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到 30000之间。

Output

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

Sample Output

4
1
2
2
10
6
5
6
5
16

Hint

【分析】

随便写了一个LCT的版本,比树链剖分慢...

现在发现LCT真是个好东西,好写又有用。

 /*
唐代白居易
《白云泉》
天平山上白云泉,云自无心水自闲。
何必奔冲山下去,更添波浪向人间。
*/
#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{
int val, sum, Max;//用来debug
int delta;
Node *parent;
Node *ch[];
}node[MAXN], *cur, _null, *null;
Node *tmp[MAXN]; bool is_root(Node* t){//判断是否是splay的根
if (t == null || (t->parent->ch[] != t && t->parent->ch[] != t)) return ;
return ;
}
//本来以为不要pushdown了,结果还是要
void pushdown(Node *t){
if (t == null) return;
if (t->delta){
t->delta = ;
if (t->ch[] != null) t->ch[]->delta ^= ;
if (t->ch[] != null) t->ch[]->delta ^= ;
swap(t->ch[], t->ch[]);
}
}
//更新
void update(Node *t){
if (t == null) return;
t->sum = t->val;
if (t->ch[] != null) t->sum += t->ch[]->sum;
if (t->ch[] != null) t->sum += t->ch[]->sum;
t->Max = max(t->val, max(t->ch[]->Max, t->ch[]->Max));
return;
}
void init(){
null = &_null;
_null.val = _null.sum = _null.Max = -INF;
_null.delta = ;
_null.parent = _null.ch[] = _null.ch[] = null; cur = node + ;
}
Node* NEW(int val){
cur->parent = cur->ch[] = cur->ch[] = null;
cur->val = cur->Max = cur->sum = val;
cur->delta = ;
return cur++;
}
void rotate(Node *t, int d){
if (is_root(t)) return;
Node *p = t->parent;
p->ch[d ^ ] = t->ch[d];
if (t->ch[d] != null) t->ch[d]->parent = p;
t->parent = p->parent;
if (p != null){
if (p->parent->ch[] == p) p->parent->ch[] = t;
else if (p->parent->ch[] == p) p->parent->ch[] = t;
}
t->ch[d] = p;
p->parent = t;
update(t);
update(p);//真逗,什么都不要
}
//将t旋转到根
void splay(Node *t){
//标记下传
int cnt = ;
tmp[] = t;
for (Node *y = t; !is_root(y); y = y->parent) tmp[cnt++] = y->parent;
while (cnt) pushdown(tmp[--cnt]); while (!is_root(t)){
Node *y = t->parent;
if (is_root(y)) rotate(t, (y->ch[] == t));
else {
int d = (y->parent->ch[] == y);
if (y->ch[d] == t) rotate(t, d ^ );
else rotate(y, d);
rotate(t, d);
}
update(t);
}
update(t);
}
Node* access(Node *t){
Node *p = null;
while (t != null){
splay(t);
if (p != null) p->parent = t;
t->ch[] = p;
update(t);
p = t;
t = t->parent;
}
return p;
}
//合并u,v所在的树
void merge(Node *u, Node *v){
access(u);
splay(u);
u->delta = ;
u->parent = v;
return;
}
void cut(Node *u, Node *v){
access(u)->delta ^= ;
//splay(u);//转到顶上就切断v就可以了
access(v);
splay(v); v->ch[]->parent = null;
v->ch[] = null;
return;
}
//找根
Node *find(Node *t){
access(t);
splay(t);
while (t->parent != null) t = t->parent;
return t;
}
bool check(Node *u, Node *v){
while (u->parent != null) u = u->parent;
while (v->parent != null) v = v->parent;
return (u == v);
}
void change(Node *l, int x){
access(l);
splay(l);
l->val = x;
update(l);
}
}splay;
int n, m;
int u[MAXN] , v[MAXN]; void init(){
splay.init();
scanf("%d", &n);
for (int i = ; i < n; i++) scanf("%d%d", &u[i], &v[i]);
for (int i = ; i <= n; i++){
int a;
scanf("%d", &a);
splay.NEW(a);
}
for (int i = ; i < n; i++)
splay.merge(splay.node + u[i], splay.node + v[i]);
}
void work(){
int m ;
scanf("%d", &m);
for (int i = ; i <= m; i++){
char str[];
scanf("%s", str);
if (str[] == 'C'){
int l, x;
scanf("%d%d", &l, &x);//将l的值改为x
splay.change(splay.node + l, x);
}else if (str[] == 'Q'){
int l, r;
scanf("%d%d", &l, &r);
if (str[] == 'S'){
splay.access(splay.node + l)->delta ^= ;//换根
splay.access(splay.node + r);
Link_Cut_Tree::Node *p = splay.find(splay.node + r);
printf("%d\n", p->sum);
}else{//求最大值
splay.access(splay.node + l)->delta ^= ;//换根
splay.access(splay.node + r);
Link_Cut_Tree::Node *p = splay.find(splay.node + r);
printf("%d\n", p->Max);
}
}
}
} int main (){ init();
work();
return ;
}

【BZOJ1036】【LCT版】树的统计Count的更多相关文章

  1. 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

    [BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...

  2. 【bzoj1036】 ZJOI2008—树的统计Count

    http://www.lydsy.com/JudgeOnline/problem.php?id=1036 (题目链接) 题意 动态维护树上两点间最大权值和权值和. Solution 裸树链剖分. 这一 ...

  3. 【bzoj1036】[ZJOI2008]树的统计Count

    题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v ...

  4. 【bzoj1036】[ZJOI2008]树的统计Count 树链剖分+线段树

    题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v ...

  5. 【BZOJ1036】[ZJOI2008] 树的统计Count(一道可怕的模板题:树剖+线段树)

    点此看题面 题解 这真的只是一道模板题:一个树链剖分套上一个线段树(令我窒息的组合). 既然是模板题,那就直接上代码吧. 代码 #include<bits/stdc++.h> #defin ...

  6. Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 11102  Solved: 4490[Submit ...

  7. [BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分

    树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设( ...

  8. Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)

    [ZJOI2008]树的统计Count ★★★ 输入文件:bzoj_1036.in 输出文件:bzoj_1036.out 简单对比 时间限制:5 s 内存限制:162 MB [题目描述] 一棵树上有n ...

  9. bzoj1036 [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 12646  Solved: 5085 [Subm ...

  10. BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)

    潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...

随机推荐

  1. 51单片机的堆栈指针(SP)

    堆栈指针(SP,Stack Pointer),专门用于指出堆栈顶部数据的地址. 那么51单片机的堆栈在什么地方呢?由于单片机中存放数据的区域有限,我们不能够专门分配一块地方做堆栈,所以就在内存(RAM ...

  2. 常见sql的error解决方法

    1.sqlserver 2008 login failed: error 18456 这是很可能是因为你没有选择sql and windows登录的模式导致sql server的用户登录失败 解决方法 ...

  3. ACM1230_火星A+B(进位的运算)

    //只要看懂火星A+B的进位关系就好了 #include<stdio.h> ]={,,,,,,,,,,,,,,,,,,,,,,,,,}; int main() { ],b[],sum[]; ...

  4. SDN基础理解

    本文转载自:http://blog.csdn.net/freezgw1985/article/details/16873677 个人觉得对很适合对SDN的入门级的概念性理解,先暂时copy一下,等研究 ...

  5. 阿里云如何添加多个网站 for Linux(绑定域名)

    我们可以通过.htaccess文件来达到一个空间帮顶多个域名的效果,即域名1访问空间上webroot下的目录1(即二级目录),域名2访问空间上webroot下的目录2,等等.二级目录名为fuli,需要 ...

  6. SonarQube4.4+Jenkins进行代码检查实例之二

    SonarQube4.4+Jenkins进行代码检查实例之二 SonarQube4.4+Jenkins进行代码检查实例之二

  7. java 检查是否是数组 检查是否是空数组 检查数组是否包含某个元素

    /** * Determine whether the given object is an array: * either an Object array or a primitive array. ...

  8. Linux命令之hwclock - 查询和设置硬件时钟

    常用参数 -r, --show         读取并打印硬件时钟(read hardware clock and print result ) -s, --hctosys      将硬件时钟同步到 ...

  9. bzoj3675: [Apio2014]序列分割

    留坑 为什么别人家的斜率优化跟我一点都不一样! 为什么斜率都要变成正的... 为什么要那么推式子 为什么不能直接做啊..... 为什么不把0去掉去秒WA啊 为什么叉积去了0也过不了啊 woc啊 #in ...

  10. Java开发中文件读取方式总结

    JAVA开发中,免不了要读文件操作,读取文件,首先就需要获取文件的路径. 路径分为绝对路径和相对路径. 在文件系统中,绝对路径都是以盘符开始的,例如C:\abc\1.txt. 什么是相对路径呢?相对路 ...