[日常摸鱼]bzoj3083遥远的国度-树链剖分
一无聊就找树剖写
题意:一颗带点权的树,三种操作:1.换根 2.链赋值 3.查询子树最小值
如果没有换根的话直接就是裸的树剖了,对于换根的操作我们可以分类讨论。
1.如果查询的$x$就是根,那答案就是整棵树的最小值。
2.如果以1为根的dfs序中,根在$x$的子树之外,那很明显$x$的子树还是原来的子树。
3.如果以1为根的dfs序中,根在$x$的子树里面的话,画个图就能发现,找到$x$的孩子中作为根的父亲那个点,答案就是整棵树把整个点的子树去掉就行了。
其他地方跟树剖没什么区别…
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long lint; const int N=100005; const lint INF=(1ll<<32); inline lint read() { lint s=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){s=s*10+c-'0';c=getchar();} return s*f; } struct edge { int to,nxt; }edges[N<<1]; int n,m,cnt,rot,tot; int head[N<<1],son[N],size[N],dep[N],top[N],dl[N],dr[N],rk[N],fa[N]; lint tr[N<<2],tag[N<<2],v[N]; #define lson (o<<1) #define rson (o<<1|1) inline void push_up(int o) { tr[o]=min(tr[lson],tr[rson]); } inline void push_down(int o) { if(tag[o]==-1)return; tag[lson]=tag[rson]=tag[o]; tr[lson]=tr[rson]=tag[o]; tag[o]=-1; } inline void build(int o,int l,int r) { tag[o]=-1; if(l==r) { tr[o]=v[rk[l]]; return; }int mid=(l+r)>>1; build(lson,l,mid);build(rson,mid+1,r); push_up(o); } inline void modify(int o,int l,int r,int ql,int qr,lint val) { if(ql<=l&&r<=qr) { tag[o]=tr[o]=val; return; }push_down(o); int mid=(l+r)>>1; if(mid>=ql)modify(lson,l,mid,ql,qr,val); if(mid+1<=qr)modify(rson,mid+1,r,ql,qr,val); push_up(o); } inline lint query(int o,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr)return tr[o]; push_down(o); int mid=(l+r)>>1;lint res=INF; if(mid>=ql)res=min(res,query(lson,l,mid,ql,qr)); if(mid+1<=qr)res=min(res,query(rson,mid+1,r,ql,qr)); return res; } #undef lson #undef rson inline void addEdge(int u,int v) { edges[++cnt]=(edge){v,head[u]}; head[u]=cnt; } #define cur edges[i].to inline void dfs1(int x) { size[x]=1; for(register int i=head[x];i;i=edges[i].nxt) if(cur!=fa[x]) { fa[cur]=x;dep[cur]=dep[x]+1; dfs1(cur);size[x]+=size[cur]; if(size[son[x]]<size[cur])son[x]=cur; } } inline void dfs2(int x,int t) { top[x]=t;dl[x]=++tot;rk[tot]=x; if(son[x])dfs2(son[x],t); for(register int i=head[x];i;i=edges[i].nxt) if(cur!=fa[x]&&cur!=son[x])dfs2(cur,cur); dr[x]=tot; } #undef cur inline void modify_link(int a,int b,int val) { while(top[a]!=top[b]) { if(dep[top[a]]<dep[top[b]])swap(a,b); modify(1,1,n,dl[top[a]],dl[a],val); a=fa[top[a]]; } if(dep[a]>dep[b])swap(a,b); modify(1,1,n,dl[a],dl[b],val); } inline lint query_tree(int x) { if(rot==x)return query(1,1,n,1,n); if(dl[x]<=dl[rot]&&dl[rot]<=dr[x]) { int y; for(register int i=head[x];i;i=edges[i].nxt) if(dl[edges[i].to]<=dl[rot]&&dl[rot]<=dr[edges[i].to]) { y=edges[i].to; break; } return min(query(1,1,n,1,dl[y]-1),query(1,1,n,dr[y]+1,n)); }else { return query(1,1,n,dl[x],dr[x]); } } int main() { n=read();m=read();rot=1; for(register int i=1;i<n;i++) { int u,v;u=read();v=read(); addEdge(u,v);addEdge(v,u); } for(register int i=1;i<=n;i++)v[i]=read(); rot=read(); dfs1(1);dfs2(1,1);build(1,1,n); for(register int i=1;i<=m;i++) { int op,x,y,val;op=read(); if(op==1) { rot=read(); }else if(op==2) { x=read();y=read();val=read(); modify_link(x,y,val); }else { x=read(); printf("%lld\n",query_tree(x)); } } }