【bzoj3306】 树 dfs序+线段树

来源:互联网 发布:手机淘宝封面模版 编辑:程序博客网 时间:2024/05/18 01:23

并不是太难,只要处理换根操作就好了,因为这棵树的形态是不变的。那么按照点1为根时的dfs序,若当前根在x点的子树外,则答案还是x的子树,若当前根是x,那么答案是整棵树,若当前的根在x的子树内,则答案就是抠掉根所在的那一枝后的答案(画个图就明白了)。


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#define maxn 100010#define inf 1000000000using namespace std;struct yts{int data;int l,r;}a[4*maxn];int e[maxn],next[2*maxn],head[maxn],to[2*maxn],g[maxn],w[maxn],in[maxn],out[maxn];int fa[maxn][20],dep[maxn];int n,m,root,num,T,tot;void addedge(int x,int y){num++;to[num]=y;next[num]=head[x];head[x]=num;}void dfs(int x){e[++tot]=x;in[x]=tot;for (int p=head[x];p;p=next[p])  if (to[p]!=g[x]) dep[to[p]]=dep[x]+1,dfs(to[p]);out[x]=tot;}void build(int i,int l,int r){a[i].l=l;a[i].r=r;if (l==r) {a[i].data=w[e[l]];return;}int mid=(l+r)/2;build(i*2,l,mid);build(i*2+1,mid+1,r);a[i].data=min(a[i*2].data,a[i*2+1].data);}void modify(int i,int x,int d){if (a[i].l==a[i].r) {a[i].data=d;return;}int mid=(a[i].l+a[i].r)/2;if (x<=mid) modify(i*2,x,d);if (mid<x) modify(i*2+1,x,d);a[i].data=min(a[i*2].data,a[i*2+1].data);}int query(int i,int l,int r){if (l>r) return inf;if (l<=a[i].l && a[i].r<=r) return a[i].data;int mid=(a[i].l+a[i].r)/2,ans=inf;if (l<=mid) ans=min(ans,query(i*2,l,r));if (mid<r) ans=min(ans,query(i*2+1,l,r));return ans;}int go_up(int x,int d){for (int i=19;i>=0;i--)  if (d&(1<<i)) x=fa[x][i];return x;}int main(){scanf("%d%d",&n,&T);for (int i=1;i<=4*n;i++) a[i].data=inf;for (int i=1;i<=n;i++)  scanf("%d%d",&g[i],&w[i]);for (int i=1;i<=n;i++)  if (g[i]) addedge(g[i],i);  else root=i;dep[1]=0;dfs(1);for (int i=1;i<=n;i++) fa[i][0]=g[i];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];    else fa[i][j]=0;build(1,1,n);while (T--){char op[5];int x,y;scanf("%s%d",op,&x);if (op[0]=='V'){scanf("%d",&y);modify(1,in[x],y);}if (op[0]=='E') root=x;if (op[0]=='Q'){if (root==x) printf("%d\n",query(1,1,n));else if (in[x]<=in[root] && out[root]<=out[x]) {int y=go_up(root,dep[root]-dep[x]-1);printf("%d\n",min(query(1,1,in[y]-1),query(1,out[y]+1,n)));}else printf("%d\n",query(1,in[x],out[x]));}}return 0;}


0 0
原创粉丝点击