2017年8月10号提高组T3 树
2017-08-14 18:32
239 查看
Description
给你一棵大小为n的有根树,每个点有点权,要求完成以下操作:V x y把点x的权值变成y
E x把有根树的根变为x
Q x查询点x的子树的最小值
Input
第一行两个整数n,m,表示点数和操作数。接下来n行,每行两个数f,v,第i行的两个数表示i的父亲和i的权值,且保证f接下来m行,每行表示一个操作。
Output
对于每个Q操作,输出一个整数表示最小值。Hint
对于30%的数据,n<=1000.对于100%的数据,n,m<=100000,权值<=10^9
Source
BY BPMSolution
不考虑修改点权和修改根是很好做的,dfs一轮就可以了。考虑修改和查询,我们可以通过dfs把树转换成序列,修改、查询的操作就变成序列上的操作了,线段树搞定。
再考虑换根。我们让1恒为根,不难发现如果询问节点x在当前根root的子树内,则x在当前根下的子树仍为x在1位根下的子树;否则,简单画一下图就可以发现,x在当前根下的子树变成了除了以1为根时x的子树外的其余部分,也就是说把dfs序去掉x以1为根时的子树那部分后,其余部分就是x在当前根下的子树。
继续用线段树来做即可。
Code
#include <stdio.h> #define rep(i, st, ed) for (int i = st; i <= ed; i += 1) #define erg(i, st) for (int i = ls[st]; i; i = e[i].next) #define min(x, y) (x)<(y)?(x):(y) #define max(x, y) (x)>(y)?(x):(y) #define INF 0x3f3f3f3f #define N 100001 #define E N struct edge{int x, y, next;}e[E]; struct treeNode{ int l, r, mn; bool operator <(treeNode b){return (l >= b.l)&&(r < b.r)||(l > b.l)&&(r <= b.r);} bool operator <=(treeNode b){return (l >= b.l)&&(r <= b.r);} }t[N << 2 | 1], rc ; int father , ls , v ; int edgeCnt = 0, rCnt = 0; inline int read(){ int x = 0; char ch = getchar(); while (ch < '0' || ch > '9'){ch = getchar();} while (ch <= '9' && ch >= '0'){x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();} return x; } inline void addEdge(int x, int y){ e[++ edgeCnt] = (edge){x, y, ls[x]}; ls[x] = edgeCnt; } inline void modify(int now, int x, int v){ if (t[now].l == t[now].r){ t[now].mn = v; return; } int mid = (t[now].l + t[now].r) >> 1; if (x <= mid){modify(now << 1, x, v);} if (x > mid){modify(now << 1 | 1, x, v);} t[now].mn = min(t[now << 1].mn, t[now << 1 | 1].mn); } inline int query(int now, int l, int r){ if (l > r){return INF;} if (t[now].l == l && t[now].r == r){return t[now].mn;} int mid = (t[now].l + t[now].r) >> 1; if (r <= mid){return query(now << 1, l, r);} if (l > mid){return query(now << 1 | 1, l, r);} return min(query(now << 1, l, mid), query(now << 1 | 1, mid + 1, r)); } inline void build(int now, int l, int r){ t[now] = (treeNode){l, r, 0}; if (l == r){return ;} int mid = (l + r) >> 1; build(now << 1, l, mid); build(now << 1 | 1, mid + 1, r); } inline void dfs(int fa, int now){ rc[now].mn = rc[now].l = rc[now].r = ++ rCnt; modify(1, rc[now].l, v[now]); erg(i, now){ dfs(now, e[i].y); rc[now].r = max(rc[now].r, rc[e[i].y].r); } } int main(void){ int n = read(), m = read(); rep(i, 1, n){ father[i] = read(); v[i] = read(); addEdge(father[i], i); } build(1, 1, n); int root = 1; dfs(0, root); rep(i, 1, m){ char ch = getchar(); int x = read(); if (ch == 'V'){ int y = read(); modify(1, rc[x].l, y); }else if (ch == 'Q'){ if (x == root){ printf("%d\n", query(1, 1, rCnt)); }else if (rc[root] < rc[x]){ int now; erg(i, x){ if (rc[root] <= rc[e[i].y]){ now = e[i].y; break; } } printf("%d\n", min(query(1, 1, rc[now].l - 1), query(1, rc[now].r + 1, rCnt))); }else{ printf("%d\n", query(1, rc[x].l, rc[x].r)); } }else if (ch == 'E'){ root = x; } } return 0; }
相关文章推荐
- 【NOIP2013提高组T3】加分二叉树
- SSL2672 2017年8月8日提高组T3 题目(二分+spfa)
- 2017年8月12日提高组T3 YMW的三角形
- SSL2710 2017年9月1号提高组 T3 玫瑰花精(线段树)
- 【NOIP2001提高组T3】统计单词个数-字符串上的动态规划
- 【NOIP 2010 提高组 T3】关押罪犯(并查集)
- C++ & Pascal——NOIP2016提高组day2 t3——愤怒的小鸟
- 2017年8月8日提高组T3 题目
- C++——NOIP2016提高组day1 t3——换教室
- 纪中集训d2 提高A组模拟 T3 JZOJ 5236 利普希茨
- 【NOIP2008提高组T3】传纸条-双线程动态规划
- [Luogu] 金秋集训营提高组 Noip模拟#2 T3 伪神
- 2017年8月9日提高组T3 难题
- Noip 提高组 2013 Day1 T3 货车运输 Kruskal+倍增
- 2017年11月1日提高组T3 极大极小值差
- 2017年8月9日提高组T3 难题
- 【SSLGZ 2677】2017年8月10号提高组T2 飞行
- C++——NOIP2015提高组day1 t3——斗地主
- SSL2689 2017年8月14日提高组T3 染色(树形dp)
- TYVJ1403(NOIP2010提高组T3)关押罪犯