SPOJ QTREE Query on a tree 边权LCT
来源:互联网 发布:wifi共享精灵for mac 编辑:程序博客网 时间:2024/05/23 11:06
题目:
https://vjudge.net/problem/SPOJ-QTREE
题意:
给定一棵有n个点的树,有以下两种操作:
CHANGE i ti: 把第i条边的权值改为ti QUERY a b: 查询ab 之间的最大边权值
思路:
边权有两种解决方案,一种把边看做一个新点,从边的两个端点像这个新点连边,然后就跟点权一样了,另一种是把边权给深度的较深的儿子,但是这样不能换根,也就是不能进行树的分离和合并。所以一般用第一种
#include <bits/stdc++.h>using namespace std;const int N = 20000 + 10, INF = 0x3f3f3f3f;struct edge{ int to, next;}g[N*5];int cnt, head[N];int son[N][2], fat[N], key[N], rev[N], maxval[N];int top, stk[N];int val[N];void add_edge(int v, int u){ g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;}void dfs(int v, int fa){ fat[v] = fa; key[v] = maxval[v] = val[v]; for(int i = head[v]; ~i; i = g[i].next) { int u = g[i].to; if(u == fa) continue; dfs(u, v); }}bool is_root(int x){ return son[fat[x]][0] != x && son[fat[x]][1] != x;}void push_up(int x){ maxval[x] = max(key[x], max(maxval[son[x][0]], maxval[son[x][1]]));}void push_down(int x){ if(rev[x]) { swap(son[x][0], son[x][1]); rev[son[x][0]] ^= 1, rev[son[x][1]] ^= 1; rev[x] ^= 1; }}void Rotate(int x){ int y = fat[x], p = son[y][0] == x; son[y][!p] = son[x][p], fat[son[x][p]] = y; if(! is_root(y)) son[fat[y]][son[fat[y]][1]==y] = x; fat[x] = fat[y]; son[x][p] = y, fat[y] = x; push_up(y);}void splay(int x){ top = 0; stk[++top] = x; for(int i = x; !is_root(i); i = fat[i]) stk[++top] = fat[i]; for(int i = top; i >= 1; i--) push_down(stk[i]); while(! is_root(x)) { int y = fat[x], z = fat[y]; if(is_root(y)) Rotate(x); else { if((x == son[y][0]) ^ (y == son[z][0])) Rotate(x), Rotate(x); else Rotate(y), Rotate(x); } } push_up(x);}void access(int x){ int y = 0; while(x) { splay(x); son[x][1] = y; push_up(x); y = x, x = fat[x]; }}void make_root(int x){ access(x); splay(x); rev[x] ^= 1;}int find_root(int x){ push_down(x); while(son[x][0]) x = son[x][0], push_down(x); return x;}void update(int x, int v){ splay(x); key[x] = v; push_up(x); //splay(x);}int query(int x, int y){ make_root(x); access(y); splay(y); return maxval[y];}//注释掉的查询:先查询出在原树中的lca,然后查询这两点到lca的两条链上的最值//调用后x是原来x和y的lca,y和son[x][1]分别存着lca的2个儿子, 即原来x和y所在的2颗子树的根//void Lca(int &x, int &y)//{// access(y); y = 0;// while(x)// {// splay(x);// if(! fat[x]) break;// son[x][1] = y;// push_up(x);// y = x, x = fat[x];// }//}//int query(int x, int y)//{// Lca(x, y);// //cout << x << " " << y << " " << son[x][1] << endl;// return max(key[x], max(maxval[y], maxval[son[x][1]]));//}void init(){ cnt = 0; memset(head, -1, sizeof head); memset(fat, 0, sizeof fat); memset(son, 0, sizeof son); memset(rev, 0, sizeof rev); memset(val, 0, sizeof val); memset(key, 0, sizeof key);}int main(){ int t, n; scanf("%d", &t); while(t--) { init(); scanf("%d", &n); int a, b, c; for(int i = 1; i <= n-1; i++) { scanf("%d%d%d", &a, &b, &c); add_edge(a, n + i); add_edge(n + i, a); add_edge(b, n + i); add_edge(n + i, b); val[n+i] = c; } dfs(1, 0); char opt[15]; while(scanf("%s", opt), opt[0] != 'D') { scanf("%d%d", &a, &b); if(opt[0] == 'C') update(a+n, b); else printf("%d\n", query(a, b)); } } return 0;}
第二种方法:
#include <bits/stdc++.h>using namespace std;const int N = 10000 + 10;struct edge{ int to, cost, next; int idx;}g[N*2];int cnt, head[N];int son[N][2], fat[N], key[N], maxval[N];int id[N];void init(){ cnt = 0; memset(head, -1, sizeof head); memset(son, 0, sizeof son); memset(fat, 0, sizeof fat); memset(key, 0, sizeof key); memset(maxval, 0, sizeof maxval);}void add_edge(int v, int u, int cost, int idx){ g[cnt].to = u, g[cnt].cost = cost, g[cnt].idx = idx, g[cnt].next = head[v], head[v] = cnt++;}void dfs(int v, int fa){ fat[v] = fa; for(int i = head[v]; ~i; i = g[i].next) { int u = g[i].to; if(u == fa) continue; id[g[i].idx] = u; key[u] = g[i].cost; dfs(u, v); }}void push_up(int x){ maxval[x] = max(key[x], max(maxval[son[x][0]], maxval[son[x][1]]));}bool is_root(int x){ return son[fat[x]][0] != x && son[fat[x]][1] != x;}void Rotate(int x){ int y = fat[x], p = son[y][0] == x; son[y][!p] = son[x][p], fat[son[x][p]] = y; if(! is_root(y)) son[fat[y]][son[fat[y]][1]==y] = x; fat[x] = fat[y]; son[x][p] = y, fat[y] = x; push_up(y);}void splay(int x){ while(! is_root(x)) { int y = fat[x], z = fat[y]; if(is_root(y)) Rotate(x); else { if((x == son[y][0]) ^ (y == son[z][0])) Rotate(x), Rotate(x); else Rotate(y), Rotate(x); } } push_up(x);}void access(int x){ int y = 0; while(x) { splay(x); son[x][1] = y; push_up(x); y = x, x = fat[x]; }}void lca(int &x, int &y){ access(y); y = 0; while(x) { splay(x); if(! fat[x]) return; son[x][1] = y; push_up(x); y = x, x = fat[x]; }}void update(int x, int v){ access(x); key[x] = v; push_up(x);}int query(int x, int y){ lca(x, y); return max(maxval[y], maxval[son[x][1]]); //这里不能取key[x]的值,因为x虽然是两点的lca,但权值却不属于两点到lca的路径上}int main(){ int t, n; char opt[20]; scanf("%d", &t); while(t--) { init(); scanf("%d", &n); int a, b, c; for(int i = 1; i <= n-1; i++) { scanf("%d%d%d", &a, &b, &c); add_edge(a, b, c, i); add_edge(b, a, c, i); } dfs(1, 0); while(scanf("%s", opt), opt[0] != 'D') { scanf("%d%d", &a, &b); if(opt[0] == 'C') update(id[a], b); else printf("%d\n", query(a, b)); } } return 0;}
阅读全文
0 0
- SPOJ QTREE Query on a tree (lct)
- SPOJ QTREE Query on a tree(边权LCT模板)
- SPOJ QTREE Query on a tree 边权LCT
- SPOJ QTREE(Query on a tree树链剖分)
- SPOJ QTREE 375. Query on a tree
- SPOJ QTREE Query on a tree --树链剖分
- [ SPOJ - QTREE]Query on a tree && 树链剖分
- SPOJ QTREE Query on a tree
- SPOJ QTREE Query on a tree 树链剖分
- SPOJ - QTREE Query on a tree(树剖)
- SPOJ QTREE Query on a tree 树链剖分
- 【树链剖分】[SPOJ-QTREE]Query on a tree
- SPOJ QTREE Query on a tree
- SPOJ QTREE - Query on a tree 【树链剖分】
- SPOJ QTREE- Query on a tree (树链剖分)
- SPOJ QTREE Query on a tree
- [spoj QTREE Query on a tree]树链剖分
- SPOJ QTREE Query on a tree
- Java 集合类及其方法
- 上拉刷新下拉加载(多条目)
- C#--简单工厂设计模式
- 《图解TCP/IP》(三)之TCP与UDP
- python中with语句的使用
- SPOJ QTREE Query on a tree 边权LCT
- python3 动态添加方法的3种情况
- vb.net 教程 20-3 控制Ie浏览器 7
- tensorflow conv2d的padding解释以及参数解释
- jQuery选择器的总结
- 试试吧
- 细说虚拟机栈
- tabLayout的深化
- iOS学习笔记-135.RunLoop03——Runloop相关类1_基础