bzoj3083: 遥远的国度
题意:给定一棵树,支持换根,路径权值覆盖,求子树最小。
思路:求子树?上树链剖分,但是换根怎么办?我们只能通过原有信息推出换根后的答案。换根不影响路径修改,所以只要考虑子树最小值的维护。
这里要分3种情况讨论
1:如果询问点是当前根,直接返回整棵树的最小值。
2:如果在原树中,当前根不在x的子树中,直接返回原树中x的子树最小值。判断x在不在y的子树中,只要通过dfs序即可,如果x的dfs序大于y,且小于等于y子树中最后一个点的dfs序,那么x就在y的子树中。
3:如果在原树中,当前根在x的子树中,那么就相当于去掉当前根所在的x的儿子的子树的整棵树(语文没学好..具体见图..)
然后这题就解决了。
#include<cstdio> #include<cstring> #include<algorithm> #define ls (p<<1) #define rs ((p<<1)|1) #define mid ((l+r)>>1) const int maxn=100010,maxm=200010,maxt=maxn<<3; using namespace std; int n,m,pre[maxm],now[maxn],son[maxm],col[maxn],tot,root; int fa[maxn],hson[maxn],w[maxn],top[maxn],dep[maxn],size[maxn],T,q,z[maxn],cnt,def[maxn],a[maxn],op,last[maxn]; void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;} struct tree{ static const int inf=2147483647; int mins[maxt],cov[maxt]; void update(int p){mins[p]=min(mins[ls],mins[rs]);} void down(int p){if (cov[p]) mins[ls]=mins[rs]=cov[ls]=cov[rs]=cov[p],cov[p]=0;} void build(int p,int l,int r){ if (l==r){mins[p]=a[l];return;} build(ls,l,mid),build(rs,mid+1,r); update(p); } void change(int p,int l,int r,int a,int b,int v){ if (l==a&&r==b){cov[p]=mins[p]=v;return;} down(p); if (b<=mid) change(ls,l,mid,a,b,v); else if (a>mid) change(rs,mid+1,r,a,b,v); else change(ls,l,mid,a,mid,v),change(rs,mid+1,r,mid+1,b,v); update(p); } int query(int p,int l,int r,int a,int b){ if (a>b) return inf; if (l==a&&r==b){return mins[p];} down(p); if (b<=mid) return query(ls,l,mid,a,b); else if (a>mid) return query(rs,mid+1,r,a,b); else return min(query(ls,l,mid,a,mid),query(rs,mid+1,r,mid+1,b)); } }Seg; void dfs(int x){ size[x]=1; for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x]){ fa[son[y]]=x,dep[son[y]]=dep[x]+1,dfs(son[y]); size[x]+=size[son[y]]; if (size[son[y]]>size[hson[x]]) hson[x]=son[y]; } } void btree(int x,int tp){ w[x]=++m,a[m]=def[x],top[x]=tp; if (hson[x]) btree(hson[x],top[x]); for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x]&&hson[x]!=son[y]) btree(son[y],son[y]); last[x]=m; } bool in(int root,int a){return w[a]>=w[root]&&w[a]<=last[root];} void cover(int a,int b,int v){ int f1=top[a],f2=top[b]; while (f1!=f2){ if (dep[f1]<dep[f2]) swap(f1,f2),swap(a,b); Seg.change(1,1,m,w[f1],w[a],v); a=fa[f1],f1=top[a]; } if (dep[a]>dep[b]) swap(a,b); Seg.change(1,1,m,w[a],w[b],v); } void answer(int x){ if (x==root) printf("%d\n",Seg.query(1,1,n,1,n)); else if (!in(x,root)) printf("%d\n",Seg.query(1,1,n,w[x],last[x])); else for (int y=now[x];y;y=pre[y]) if (in(son[y],root)&&son[y]!=fa[x]){ printf("%d\n",min(Seg.query(1,1,n,1,w[son[y]]-1),Seg.query(1,1,n,last[son[y]]+1,n))); break; } } int main(){ // freopen("country.in","r",stdin);freopen("country.out","w",stdout); scanf("%d%d",&n,&q); for (int i=1,a,b;i<n;i++) scanf("%d%d",&a,&b),add(a,b),add(b,a); for (int i=1;i<=n;i++) scanf("%d",&def[i]); scanf("%d",&root); dfs(root),btree(root,root);Seg.build(1,1,m); for (int i=1,a,b,c;i<=q;i++){ scanf("%d",&op); if (op==1) scanf("%d",&a),root=a; else if (op==2) scanf("%d%d%d",&a,&b,&c),cover(a,b,c); else scanf("%d",&a),answer(a); } // fclose(stdout); return 0; }