3306: 树
时间限制: 10 Sec 内存限制: 256 MB题目描述
给定一棵大小为 n 的有根点权树,支持以下操作:
• 换根
• 修改点权
• 查询子树最小值
输入
第一行两个整数 n, Q ,分别表示树的大小和操作数。
接下来n行,每行两个整数f,v,第i+1行的两个数表示点i的父亲和点i的权。保证f < i。如 果f = 0,那么i为根。输入数据保证只有i = 1时,f = 0。
接下来 m 行,为以下格式中的一种:
• V x y表示把点x的权改为y
• E x 表示把有根树的根改为点 x
• Q x 表示查询点 x 的子树最小值
输出
对于每个 Q ,输出子树最小值。
样例输入
0 1
1 2
1 3
Q 1
V 1 6
Q 1
V 2 5
Q 1
V 3 4
Q 1
样例输出
2
3
4
提示
对于 100% 的数据:n, Q ≤ 10^5。
思路:
看到这个题时,有没有脑子里一下子蹦出这样一个念头:这个题用线段树做!
对,的确是这样。但有人又要问了:线段树怎么用?
碍于各种原因,我们在这先不说线段树的做法,到后卖弄我们开始学线段树的时候,我们再来用线段树A这道题。
我们在前面一直在刷lca题嘛,所以我们把这道题弱化一下:只有换根和查询最小值的操作。
那这样有没有感觉这个题变简单了很多啊?
好,那我们就来秒一下这个题吧!
具体思路:我们考虑这样一个问题:若果没有换跟操作,那我们是不是就可以用一遍dfs求出这道题了?
那我们接下来考虑根节点s与查询节点x的关系。
如果:lca(s,x)!=x,那答案就是以x为根的子树的最小值
若s==x,那x即为最小值。
若lca(x,s)==x,那答案就是除去点x包含点s的子数的最小值。
前两种情况可以预先处理前缀和后缀。
由于一个子树在dfs序上对应的是一段区间,那这样剩下的部分是不是就是一段的前缀+一段后缀啊?!
所以我们优先处理前缀后缀的最小值来解决问题。
代码:
#include<vector> #include<stdio.h> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 1000 using namespace std; vector<int>vec[N]; int fa[N][N],A[N],B[N]; int deep[N],C[N],en[N],cnt,a[N]; int n,m,top[N],ans,dfn[N],st[N],x,y; string s; int lca(int x,int y) { if(deep[x]>deep[y]) swap(x,y); for(int i=20;i>=0;i--) if(deep[fa[y][i]]>=deep[x]) y=fa[y][i]; if(x==y) return x; for(int i=20;i>=0;i--) if(fa[y][i]!=fa[x][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } void dfs(int x) { st[x]=++cnt; dfn[cnt]=x; C[x]=a[x]; for(int i=0;i<vec[x].size();i++) { deep[vec[x][i]]=deep[x]+1; dfs(vec[x][i]); C[x]=min(C[x],C[vec[x][i]]); } en[x]=cnt; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d",&fa[i][0],&a[i]); vec[fa[i][0]].push_back(i); } int S=deep[1]=1;dfs(S); A[0]=B[n+1]=1e9; for(int i=1;i<=n;i++) A[i]=min(A[i-1],a[dfn[i]]); for(int i=n;i>=1;i--) B[i]=min(B[i+1],a[dfn[i]]); int T,t; for(int i=1;i<=m;i++) { cin>>s; if(s[0]=='E') scanf("%d",&S); else { scanf("%d",&T); t=lca(S,T); if(S==T) printf("%d\n",C[1]); else if(t!=T) printf("%d\n",C[T]); else { int ss=S; for(int i=20;i>=0;i--) if(deep[fa[ss][i]]>deep[T]) ss=fa[ss][i]; printf("%d\n",min(A[st[ss]-1],B[en[ss]+1])); } } } return 0; }