Problem Description
You are given a tree with N nodes which are numbered by integers 1..N. Each node is associated with an integer as the weight.

Your task is to deal with M operations of 4 types:

1.Delete an edge (x, y) from the tree, and then add a new edge (a, b). We ensure that it still constitutes a tree after adding the new edge.

2.Given two nodes a and b in the tree, change the weights of all the nodes on the path connecting node a and b (including node a and b) to a particular value x.

3.Given two nodes a and b in the tree, increase the weights of all the nodes on the path connecting node a and b (including node a and b) by a particular value d.

4.Given two nodes a and b in the tree, compute the second largest weight on the path connecting node a and b (including node a and b), and the number of times this weight occurs on the path. Note that here we need the strict second largest weight. For instance, the strict second largest weight of {3, 5, 2, 5, 3} is 3.

 
Input
The first line contains an integer T (T<=3), which means there are T test cases in the input.

For each test case, the first line contains two integers N and M (N, M<=10^5). The second line contains N integers, and the i-th integer is the weight of the i-th node in the tree (their absolute values are not larger than 10^4).

In next N-1 lines, there are two integers a and b (1<=a, b<=N), which means there exists an edge connecting node a and b.

The next M lines describe the operations you have to deal with. In each line the first integer is c (1<=c<=4), which indicates the type of operation.

If c = 1, there are four integers x, y, a, b (1<= x, y, a, b <=N) after c.
If c = 2, there are three integers a, b, x (1<= a, b<=N, |x|<=10^4) after c.
If c = 3, there are three integers a, b, d (1<= a, b<=N, |d|<=10^4) after c.
If c = 4 (it is a query operation), there are two integers a, b (1<= a, b<=N) after c.

All these parameters have the same meaning as described in problem description.

 
Output
For each test case, first output "Case #x:"" (x means case ID) in a separate line.

For each query operation, output two values: the second largest weight and the number of times it occurs. If the weights of nodes on that path are all the same, just output "ALL SAME" (without quotes).

题目大意:维护一棵树,每次删边加边、给一条路径的所有点赋一个值、给一条路径的所有点加上一个值,或询问一条路径上的第二大值及其在这条路径上的出现次数。

思路:算是LCT的模板题吧,维护每个区间的第一大值和第一大值的出现次数,第二大值和第二大值的出现次数。

PS:终于搞出了一个指针版,新模板出来啦~~~

犯过的错误:

1、LCT里splay的旋转和普通splay的旋转有所不同。

2、不能更新超级儿子 nil 的最值。

代码(2859MS):

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
#define FOR(i, n) for(int i = 0; i < n; ++i) const int MAXV = ;
const int MAXE = MAXV << ;
const int INF = 0x3f3f3f3f;
const int NINF = -INF; struct LCT {
struct Node {
Node *ch[], *fa;
int val, set, add;
int max[], cnt[], size;
bool rt, rev;
} statePool[MAXV], *nil;
int ncnt; int head[MAXV], val[MAXV], ecnt;
int to[MAXE], next[MAXE];
int n, m, T;
Node *ptr[MAXV]; LCT() {
ptr[] = nil = statePool;
nil->size = ;
FOR(k, ) nil->max[k] = NINF;
} void init() {
memset(head + , -, n * sizeof(int));
ncnt = ;
ecnt = ;
} void add_edge(int u, int v) {
to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; next[ecnt] = head[v]; head[v] = ecnt++;
} Node* new_node(int val, Node *f) {
Node* x = &statePool[ncnt++];
x->ch[] = x->ch[] = nil; x->fa = f;
x->val = val; x->set = NINF; x->add = ;
x->max[] = val; x->cnt[] = ;
x->max[] = NINF;
x->size = ;
x->rt = true; x->rev = false;
return x;
} void dfs(int u, int f) {
ptr[u] = new_node(val[u], ptr[f]);
for(int p = head[u]; ~p; p = next[p]) {
int v = to[p];
if(v == f) continue;
dfs(v, u);
}
} void get_max(int &a, int &b, int c) {
if(a != c) {
if(b < c) swap(b, c);
if(a < b) swap(a, b);
}
} void cnt_max(int a, int &cnt, int b, int bcnt) {
if(a != NINF && a == b) cnt += bcnt;
} void update(Node *x) {
x->size = x->ch[]->size + x->ch[]->size + ; x->max[] = x->val; x->max[] = NINF;
FOR(i, ) FOR(j, )
get_max(x->max[], x->max[], x->ch[i]->max[j]); FOR(k, ) x->cnt[k] = ;
FOR(k, ) cnt_max(x->max[k], x->cnt[k], x->val, );
FOR(k, ) FOR(i, ) FOR(j, )
cnt_max(x->max[k], x->cnt[k], x->ch[i]->max[j], x->ch[i]->cnt[j]);
} void rotate(Node *x) {
Node *y = x->fa;
int t = (y->ch[] == x); if(y->rt) y->rt = false, x->rt = true;
else y->fa->ch[y->fa->ch[] == y] = x;
x->fa = y->fa; (y->ch[t] = x->ch[t ^ ])->fa = y;
(x->ch[t ^ ] = y)->fa = x;
update(y);
} void update_set(Node *x, int val) {
if(x == nil) return ;
x->add = ;
x->val = x->set = val;
x->max[] = val; x->cnt[] = x->size;
x->max[] = NINF;
} void update_add(Node *x, int val) {
if(x == nil) return ;
x->add += val;
x->val += val;
FOR(k, ) if(x->max[k] != NINF)
x->max[k] += val;
} void update_rev(Node *x) {
if(x == nil) return ;
x->rev = !x->rev;
swap(x->ch[], x->ch[]);
} void pushdown(Node *x) {
if(x->set != NINF) {
FOR(k, ) update_set(x->ch[k], x->set);
x->set = NINF;
}
if(x->add != ) {
FOR(k, ) update_add(x->ch[k], x->add);
x->add = ;
}
if(x->rev) {
FOR(k, ) update_rev(x->ch[k]);
x->rev = false;
}
} void push(Node *x) {
if(!x->rt) push(x->fa);
pushdown(x);
} void splay(Node *x) {
push(x);
while(!x->rt) {
Node *f = x->fa, *ff = f->fa;
if(!f->rt) rotate(((ff->ch[] == f) && (f->ch[] == x)) ? f : x);
rotate(x);
}
update(x);
} Node* access(Node *x) {
Node *y = nil;
while(x != nil) {
splay(x);
x->ch[]->rt = true;
(x->ch[] = y)->rt = false;
update(x);
y = x; x = x->fa;
}
return y;
} void be_root(Node *x) {
access(x);
splay(x);
update_rev(x);
} void link(Node *x, Node *y) {
be_root(x);
x->fa = y;
} void cut(Node *x, Node *y) {
be_root(x);
access(x);
splay(y);
y->fa = nil;
} void modify_add(Node *x, Node *y, int w) {
be_root(x);
update_add(access(y), w);
} void modify_set(Node *x, Node *y, int w) {
be_root(x);
update_set(access(y), w);
} void query(Node *x, Node *y) {
be_root(x);
Node *r = access(y);
if(r->max[] == NINF) puts("ALL SAME");
else printf("%d %d\n", r->max[], r->cnt[]);
} void work() {
scanf("%d", &T);
for(int t = ; t <= T; ++t) {
scanf("%d%d", &n, &m);
init();
for(int i = ; i <= n; ++i) scanf("%d", &val[i]);
for(int i = , u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
add_edge(u, v);
}
dfs(, );
printf("Case #%d:\n", t);
for(int i = , x, y, a, b, op; i < m; ++i) {
scanf("%d", &op);
if(op == ) {
scanf("%d%d%d%d", &x, &y, &a, &b);
cut(ptr[x], ptr[y]);
link(ptr[a], ptr[b]);
} else if(op == ) {
scanf("%d%d%d", &a, &b, &x);
modify_set(ptr[a], ptr[b], x);
} else if(op == ) {
scanf("%d%d%d", &a, &b, &x);
modify_add(ptr[a], ptr[b], x);
} else {
scanf("%d%d", &a, &b);
query(ptr[a], ptr[b]);
}
}
}
}
} S; int main() {
S.work();
}

HDU 5002 Tree(动态树LCT)(2014 ACM/ICPC Asia Regional Anshan Online)的更多相关文章

  1. HDU 5000 2014 ACM/ICPC Asia Regional Anshan Online DP

    Clone Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/65536K (Java/Other) Total Submiss ...

  2. HDU 5000 Clone(离散数学+DP)(2014 ACM/ICPC Asia Regional Anshan Online)

    Problem Description After eating food from Chernobyl, DRD got a super power: he could clone himself ...

  3. 2014 ACM/ICPC Asia Regional Anshan Online

    默默的签到 Osu! http://acm.hdu.edu.cn/showproblem.php?pid=5003 #include<cstdio> #include<algorit ...

  4. hdu 5016 点分治(2014 ACM/ICPC Asia Regional Xi'an Online)

    Mart Master II Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  5. HDU 5875 Function 【倍增】 (2016 ACM/ICPC Asia Regional Dalian Online)

    Function Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total ...

  6. HDU 5029 Relief grain(离线+线段树+启发式合并)(2014 ACM/ICPC Asia Regional Guangzhou Online)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5029 Problem Description The soil is cracking up beca ...

  7. HDU 5052 Yaoge’s maximum profit 光秃秃的树链拆分 2014 ACM/ICPC Asia Regional Shanghai Online

    意甲冠军: 特定n小点的树权. 以下n每一行给出了正确的一点点来表达一个销售点每只鸡价格的格 以下n-1行给出了树的侧 以下Q操作 Q行 u, v, val 从u走v,程中能够买一个鸡腿,然后到后面卖 ...

  8. hdu 5877 线段树(2016 ACM/ICPC Asia Regional Dalian Online)

    Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total ...

  9. HDU 5010 Get the Nut(2014 ACM/ICPC Asia Regional Xi'an Online)

    思路:广搜, 因为空格加上动物最多只有32个那么对这32个进行编号,就能可以用一个数字来表示状态了,因为只有 ‘P’   'S' 'M' '.' 那么就可以用4进制刚好可以用64位表示. 接下去每次就 ...

随机推荐

  1. Python之if语句

    计算机之所以能做很多自动化的任务,因为它可以自己做条件判断. 比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,可以用if语句实现: age = 20 if age >= 18: ...

  2. python 之 range()

    range 是一个类,这个类用来实例化生成一个有序的整数序列. range类中定义了__iter__()特殊方法,说明range 类的实例对象都支持迭代. __len__()方法说明 range对象可 ...

  3. Compiling Inkscape on Windows

    http://wiki.inkscape.org/wiki/index.php/Compiling_Inkscape_on_Windows http://www.oschina.net/news/80 ...

  4. BAT 遍历文件夹和子文件夹下所有文件

    echo off & color 0A ::指定起始文件夹 set DIR="%cd%" echo DIR=%DIR% :: 参数 /R 表示需要遍历子文件夹,去掉表示不遍 ...

  5. python入门 2014-3-21

    刚吃完饭,写一会python 准备去上课,哇咔咔! 1.python是动态类型语言,也就是说 不需要预先声明变量的类型. 不支持 自增++ , 自减--

  6. SQl中Left Join 、Right Join 、Inner Join与Ful Join

    1 left join 左外连接:查询结果以左表数据为准.假如左表有四条数据,右表有三条数据,则查询结果为四条,且都是左表中有的数据. 例如: EMP表: SAL表: 左连接 左连接,表EMP是主表, ...

  7. 关于actionscript中新建一个sprite,设置大小(宽高)的问题。

    有一定as3开发经验的童鞋应该知道,新建一个sprite,是无法设置大小的,即时设置了,也不会生效,宽高还是为0,据说反而有副作用(http://www.cnblogs.com/yjmyzz/arch ...

  8. windows安装java环境

    1.下载安装jdk:以jdk-8u66-windows-x64为例. 2.JDK的环境变量配置 用鼠标右击“计算机”,选择“属性”->“高级系统设置”->“环境变量”->“系统变量” ...

  9. 一个短小的JS函数,用来得到仅仅包含不重复元素的数组

    下面函数主要利用了数组的sort方法,之后的逻辑是看最后一个元素是否等于要添加的元素,如果不是就往尾后加. 这个做法的效率等于sort方法的效率,还过得去. 代码: <!DOCTYPE HTML ...

  10. LeetCode H-Index II

    原题链接在这里:https://leetcode.com/problems/h-index-ii/ 题目: Follow up for H-Index: What if the citations a ...