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. 【转】Java ConcurrentModificationException 异常分析与解决方案--还不错

    原文网址:http://www.2cto.com/kf/201403/286536.html 一.单线程 1. 异常情况举例 只要抛出出现异常,可以肯定的是代码一定有错误的地方.先来看看都有哪些情况会 ...

  2. C#调用Web Service时的身份验证

    原理:webservice所在的系统中,在系统域中建立用于登录的软件的用户和密码,软件登录时将用户名.密码和登录的本机的域的名字通过webService的NetworkCredential传递到web ...

  3. [工具] slf4j-api、slf4j-log4j12以及log4j之间的关系

    几乎在每个jar包里都可以看到log4j的身影,在多个子工程构成项目中,slf4j相关的冲突时不时就跳出来让你不爽,那么slf4j-api.slf4j-log4j12还有log4j是什么关系?     ...

  4. 《University Calculus》-chape6-定积分的应用-平面曲线长度

    平面曲线的长度: 积分的重要作用体现在处理曲线和曲面. 在这里我们讨论平面中一条用参数形式表达的曲线:x=f(t),y=g(t),a≤t≤b. 如图. y=f(x)形式的弧长计算: 之前我们讨论过平面 ...

  5. Spark RDD概念学习系列之Spark Hash Shuffle内幕彻底解密(二十)

    本博文的主要内容: 1.Hash Shuffle彻底解密 2.Shuffle Pluggable解密 3.Sorted Shuffle解密 4.Shuffle性能优化 一:到底什么是Shuffle? ...

  6. IDEA新建SpringMVC项目报错解决办法

    网页运行的错误: HTTP Status 500 - Handler processing failed; nested exception is java.lang.NoClassDefFoundE ...

  7. Linux的定时任务

    分两种:一次性的定时任务.周期性的定时任务. 一次性的定时任务,又称at定时任务,命令为atd ,这里d是deamon的首字母,守护的意思,指守护进程:其实很多程序都是以d结尾,如httpd.memc ...

  8. 平时Error记录

    The Windows Firewall on this machine is currently 1.This row already belongs to another table. DataT ...

  9. pomelo 服务器之间的通信

    master服务器在启动的时候会启动mater服务,生成一个MasterAgent,作为中心服务器. 然后所有服务器,包括mater服务器,都会启动monitor服务,生成一个MonitorAgent ...

  10. winform Execl数据 导入到数据库(SQL) 分类: WinForm C# 2014-05-09 20:52 191人阅读 评论(0) 收藏

    首先,看一下我的窗体设计: 要插入的Excel表: 编码 名称 联系人 电话 省市 备注 100 100线 张三 12345678910 北京 测试 101 101线 张三 12345678910 上 ...