bzoj3306: 树(dfs序+倍增+线段树)
Posted Sakits
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3306: 树(dfs序+倍增+线段树)相关的知识,希望对你有一定的参考价值。
比较傻逼的一道题...
显然求子树最小值就是求出dfs序用线段树维护嘛
换根的时候树的形态不会改变,所以我们可以根据相对于根的位置分类讨论。
如果询问的x是根就直接输出整棵树的最小值。
如果询问的x是根在原树上的子节点,直接输出子树的最小值。
如果询问的x是根在原树上的祖先,那么就要输出整棵树去掉x在原树上那个包含根的子节点的子树的答案。
至于怎么求x在原树上那个包含根的子节点,可以用倍增。
但是我发现直接遍历x的子节点居然不会被卡,而且还跑到了第一页嘿嘿嘿
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> const int maxn=500010, inf=1e9; struct poi{int too, pre;}e[maxn]; struct tjm{int sum;}tree[maxn<<2]; int n, q, x, y, tot, tott, root; int a[maxn], last[maxn], l[maxn], r[maxn], pos[maxn], d[maxn], f[maxn][20]; char s[2]; inline void read(int &k) { int f=1; k=0; char c=getchar(); while(c<‘0‘ || c>‘9‘) c==‘-‘ && (f=-1), c=getchar(); while(c<=‘9‘ && c>=‘0‘) k=k*10+c-‘0‘, c=getchar(); k*=f; } inline void add(int x, int y){e[++tot].too=y; e[tot].pre=last[x]; last[x]=tot;} void dfs(int x) { l[x]=++tott; pos[tott]=x; d[x]=d[f[x][0]]+1; for(int i=last[x];i;i=e[i].pre) f[e[i].too][0]=x, dfs(e[i].too); r[x]=tott; } inline int min(int a, int b) {return a<b?a:b;} inline void up(int x) {tree[x].sum=min(tree[x<<1].sum, tree[x<<1|1].sum);} void build(int x, int l, int r) { if(l==r) {tree[x].sum=pos[l]?a[pos[l]]:inf; return;} int mid=(l+r)>>1; build(x<<1, l, mid); build(x<<1|1, mid+1, r); up(x); } void update(int x, int l, int r, int cx, int delta) { if(l==r) {tree[x].sum=delta; return;} int mid=(l+r)>>1; if(cx<=mid) update(x<<1, l, mid, cx, delta); else update(x<<1|1, mid+1, r, cx, delta); up(x); } int query(int x, int l, int r, int cl, int cr) { if(cl>cr) return inf; if(cl<=l && r<=cr) return tree[x].sum; int mid=(l+r)>>1, ans=inf; if(cl<=mid) ans=query(x<<1, l, mid, cl, cr); if(cr>mid) ans=min(ans, query(x<<1|1, mid+1, r, cl, cr)); return ans; } inline int solve(int x) { if(x==root) return tree[1].sum; if(l[x]>l[root] || r[x]<l[root]) return query(1, 1, n, l[x], r[x]); int now=root; for(int i=16;i>=0;i--) if(d[f[now][i]]>x) now=f[now][i]; return min(query(1, 1, n, 1, l[now]-1), query(1, 1, n, r[now]+1, n)); } int main() { read(n); read(q); for(int i=1;i<=n;i++) { read(x); read(a[i]); if(x) add(x, i); } dfs(root=1); build(1, 1, n); for(int j=1;j<=16;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; for(int i=1;i<=q;i++) { scanf("%s", s+1); if(s[1]==‘V‘) read(x), read(y), update(1, 1, n, l[x], y); else if(s[1]==‘E‘) read(root); else read(x), printf("%d\n", solve(x)); } }
以上是关于bzoj3306: 树(dfs序+倍增+线段树)的主要内容,如果未能解决你的问题,请参考以下文章