POJ 3237 Tree 树链剖分
2016-05-15 23:48
369 查看
题目:http://poj.org/problem?id=3237
题意:给定一棵树,有边权,然后有一定数量的操作:第一种操作是改变第i条边(输入顺序)的边权为v,第二种操作是对某两点路径上的所有边权取反,第三种操作求两点间路径的最大权值
思路:树链剖分啊,然后线段树维护区间最大值和最小值,因为取反操作会使最大变最小,最小变最大,在更新最大最小值注意,一不小心就哇了
题意:给定一棵树,有边权,然后有一定数量的操作:第一种操作是改变第i条边(输入顺序)的边权为v,第二种操作是对某两点路径上的所有边权取反,第三种操作求两点间路径的最大权值
思路:树链剖分啊,然后线段树维护区间最大值和最小值,因为取反操作会使最大变最小,最小变最大,在更新最大最小值注意,一不小心就哇了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int INF = 0x3f3f3f3f; const int N = 10010; struct edge { int to, next; }g[N*2]; struct node { int l, r, maxx, minn, mark; }s[N*4]; int dep , top , siz , id , fat , son , head ; int d [3], val ; int n, num, cnt; void add_edge(int v, int u) { g[cnt].to = u; g[cnt].next = head[v]; head[v] = cnt++; } void dfs1(int v, int fa, int d) { dep[v] = d, siz[v] = 1, fat[v] = fa, son[v] = 0; for(int i = head[v]; i != -1; i = g[i].next) { int u = g[i].to; if(u != fa) { dfs1(u, v, d + 1); siz[v] += siz[u]; if(siz[son[v]] < siz[u]) son[v] = u; } } } void dfs2(int v, int tp) { top[v] = tp, id[v] = ++num; if(son[v]) dfs2(son[v], tp); for(int i = head[v]; i != -1; i = g[i].next) { int u = g[i].to; if(u != fat[v] && u != son[v]) dfs2(u, u); } } void push_up(int k) { s[k].maxx = max(s[k<<1].maxx, s[k<<1|1].maxx); s[k].minn = min(s[k<<1].minn, s[k<<1|1].minn); } void push_down(int k) { int tmp; if(s[k].mark & 1) { s[k<<1].mark += s[k].mark; s[k<<1|1].mark += s[k].mark; /*最大变最小,最小变最大*/ tmp = -s[k<<1].maxx; s[k<<1].maxx = -s[k<<1].minn; s[k<<1].minn = tmp; tmp = -s[k<<1|1].maxx; s[k<<1|1].maxx = -s[k<<1|1].minn; s[k<<1|1].minn = tmp; s[k].mark = 0; } } void build(int l, int r, int k) { s[k].l = l, s[k].r = r, s[k].mark = 0; if(l == r) { s[k].maxx = s[k].minn = val[l]; return; } int mid = (l + r) >> 1; build(l, mid, k << 1); build(mid + 1, r, k << 1|1); push_up(k); } void update(int l, int r, int k) { if(l <= s[k].l && s[k].r <= r) { /*最大变最小,最小变最大*/ int tmp = -s[k].maxx; s[k].maxx = -s[k].minn; s[k].minn = tmp; s[k].mark++; return; } push_down(k); int mid = (s[k].l + s[k].r) >> 1; if(l <= mid) update(l, r, k << 1); if(r > mid) update(l, r, k << 1|1); push_up(k); } void renew(int v, int u) { int t1 = top[v], t2 = top[u]; while(t1 != t2) { if(dep[t1] < dep[t2]) swap(t1, t2), swap(v, u); update(id[t1], id[v], 1); v = fat[t1], t1 = top[v]; } if(v == u) return; if(dep[v] > dep[u]) swap(v, u); update(id[son[v]], id[u], 1); } void update_edge(int x, int c, int k) { if(s[k].l == s[k].r) { s[k].maxx = s[k].minn = c; return; } push_down(k); int mid = (s[k].l + s[k].r) >> 1; if(x <= mid) update_edge(x, c, k << 1); else update_edge(x, c, k << 1|1); push_up(k); } int query(int l, int r, int k) { if(l <= s[k].l && s[k].r <= r) return s[k].maxx; push_down(k); int mid = (s[k].l + s[k].r) >> 1; int ans = -INF; if(l <= mid) ans = max(ans, query(l, r, k << 1)); if(r > mid) ans = max(ans, query(l, r, k << 1|1)); push_up(k); return ans; } int seek(int v, int u) { int t1 = top[v], t2 = top[u], ans = -INF; while(t1 != t2) { if(dep[t1] < dep[t2]) swap(t1, t2), swap(v, u); ans = max(ans, query(id[t1], id[v], 1)); v = fat[t1], t1 = top[v]; } if(v == u) return ans; if(dep[v] > dep[u]) swap(v, u); return max(ans, query(id[son[v]], id[u], 1)); } void slove() { char str[20]; int a, b; while(scanf(" %s", str), str[0] != 'D') { scanf("%d%d", &a, &b); if(str[0] == 'C') update_edge(id[d[a][1]], b, 1); else if(str[0] == 'N') renew(a, b); else if(str[0] == 'Q') printf("%d\n", seek(a, b)); } } int main() { int t; scanf("%d", &t); while(t--) { num = cnt = 0; memset(head, -1, sizeof head); scanf("%d", &n); for(int i = 1; i <= n - 1; i++) { scanf("%d%d%d", &d[i][0], &d[i][1], &d[i][2]); add_edge(d[i][0], d[i][1]); add_edge(d[i][1], d[i][0]); } dfs1(1, 0, 1); dfs2(1, 1); for(int i = 1; i <= n - 1; i++) { if(dep[d[i][0]] > dep[d[i][1]]) swap(d[i][0], d[i][1]); val[id[d[i][1]]] = d[i][2]; } build(1, num, 1); slove(); } return 0; }
相关文章推荐
- [安卓开发] 带滚动条的多屏滑动-IndicatorFragmentActivity 修改优化版|添加底部图片变化
- Android ActionBar使用
- 第10.11周项目 继承和派生(补充)4
- 【LeetCode】344. Reverse String 解题报告
- 半数集问题
- swift简单动画demo
- tomcat6.0配置
- MySQL5.6主从复制的配置(CentOS-6.6+MySQL-5.6)(二)
- 模板
- RxJava源代码剖析
- 安卓开发之java基础笔记8常用API
- jquery 实现 点击按钮后倒计时效果,多用于实现发送手机验证码
- Word Pattern
- Unity3D重要的类
- 分分钟修改Android keystore
- struts2的form等表单布局问题,去掉其自动生成的<table><tr><td>标签
- 电商系统的高并发设计和挑战
- PHP7 + Apache2.4 + MySQL 5.7 + Windows7
- Eclipse快捷键大全
- AngularJS学习笔记之依赖注入