Description
给定一棵大小为 n 的有根点权树,支持以下操作:
换根
修改点权
查询子树最小值
Input
第一行两个整数
接下来
n
行,每行两个整数
接下来 m 行,为以下格式中的一种:
Vxy 表示把点 x 的权改为y Ex 表示把有根树的根改为点 x
Qx 表示查询点 x 的子树最小值
Output
对于每个
Q ,输出子树最小值。Sample Input
3 7 0 1 1 2 1 3 Q 1 V 1 6 Q 1 V 2 5 Q 1 V 3 4 Q 1
Sample Output
1 2 3 4
HINT
对于 100% 的数据: n,Q≤105
solution
这道题先把整个树dfs一下,搞出dfs序来,那修改点权和查询最小值就是裸的线段树了
就是换根看上去有点难,来考虑一下根对查询操作的影响
假设我们要查的那个节点是 x ,根为
root if(x=root) 显然这个时候就是查询整棵树的最小值
if(x≠root) ,这个时候又要分两种情况来考虑
如果我们把根换到不是 x 的子树的点,那么这个时候对
x 是没什么影响
如我我们把根从 root 换到 a ,并不会影响到
x 的子树,所以这个时候和平常一样query就好如果我们把根换到属于 x 的子树的点
一开始如果树长这个样
- 我们把根换到属于
x 的子树的点 a ,那树就成了这个样子
对比一下上面那个图,我们发现换根之后要查询的范围就是不换根之前所有的店除了
a 和 a <script type="math/tex" id="MathJax-Element-3143">a</script> 的子树把这个推广一下就可以了
code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; template<typename T> void input(T &x) { x=0; T a=1; register char c=getchar(); for(;c<'0'||c>'9';c=getchar()) if(c=='-') a=-1; for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; x*=a; return; } #define MAXN 100010 struct Edge { int u,v,next; Edge(int u=0,int v=0,int next=0): u(u),v(v),next(next) {} }; Edge edge[MAXN]; int head[MAXN],cnt=0; void addedge(int u,int v) { edge[++cnt]=Edge(u,v,head[u]); head[u]=cnt; return; } int dfn[MAXN],last[MAXN],order[MAXN],timee; int fa[MAXN][21],depth[MAXN]; void dfs(int u) { order[++timee]=u; dfn[u]=timee; for(int i=head[u];i;i=edge[i].next) if(edge[i].v!=fa[u][0]) { depth[edge[i].v]=depth[u]+1; dfs(edge[i].v); } last[u]=timee; return; } int w[MAXN]; struct Segment_Tree { int l,r,Min; }; Segment_Tree t[MAXN<<2]; void updata(int now) { t[now].Min=min(t[now<<1].Min,t[now<<1|1].Min); return; } void build(int now,int l,int r) { t[now].l=l,t[now].r=r; if(l==r) { t[now].Min=w[order[l]]; return; } int mid=l+r>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); updata(now); return; } void Modify(int now,int pos,int x) { int l=t[now].l,r=t[now].r; if(l==r) { t[now].Min=x; return; } int mid=l+r>>1; if(pos<=mid) Modify(now<<1,pos,x); else Modify(now<<1|1,pos,x); updata(now); return; } #define inf 2147483647 int query(int now,int L,int R) { if(L>R) return inf; int l=t[now].l,r=t[now].r; if(l==L&&R==r) return t[now].Min; int mid=l+r>>1; if(R<=mid) return query(now<<1,L,R); else if(L>mid) return query(now<<1|1,L,R); else { int a=query(now<<1,L,mid), b=query(now<<1|1,mid+1,R); return min(a,b); } } int up(int x,int depth) { for(int i=19;i>=0;i--) if(depth&(1<<i)) x=fa[x][i]; return x; } int main() { int n,T,root=1; input(n),input(T); input(fa[1][0]),input(w[1]); for(int i=2;i<=n;i++) { input(fa[i][0]),input(w[i]); addedge(fa[i][0],i); } dfs(1); for(int j=1;j<=19;j++) for(int i=1;i<=n;i++) if(fa[i][j-1]) fa[i][j]=fa[fa[i][j-1]][j-1]; build(1,1,n); char op[3]; int x,y; while(T--) { scanf("%s",op); input(x); if(op[0]=='V') { input(y); Modify(1,dfn[x],y); } else if(op[0]=='E') root=x; else if(root==x) printf("%d\n",query(1,1,n)); else if(dfn[x]<=dfn[root]&&last[root]<=last[x]) { y=up(root,depth[root]-depth[x]-1); printf("%d\n",min(query(1,1,dfn[y]-1),query(1,last[y]+1,n))); } else printf("%d\n",query(1,dfn[x],last[x])); } return 0; }