bzoj3083: 遥远的国度
题意:有棵树,每个点有权值,三种操作,1,修改根,2.把a到b的路径上的点权值修改为c,3,查询以a为子树的最小权值
题解:毒瘤树链剖分,树链剖分是能处理链和子树的修改查询的,因为树链剖分本质还是dfs序线段树,然后现在问题就变成了换根,假设根为root
1.root为a,直接查询整棵树,2.lca(root,a)!=a,直接查询a子树,3.lca(root,a)==a,这时a是root的祖先,需要查询的子树是除了a到root路径上的直接儿子的子树的整棵树,分成两段即可,假设直接儿子是x,那么就是(1,l[x]-1),(r[x]+1,n);
/**************************************************************
Problem: 3083
User: walfy
Language: C++
Result: Accepted
Time:6272 ms
Memory:26228 kb
****************************************************************/
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize(4)
//#pragma GCC optimize("unroll-loops")
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<bits/stdc++.h>
#define fi first
#define se second
#define db double
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000009
#define ld long double
//#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define ull unsigned long long
//#define base 1000000000000000000
#define fin freopen("a.txt","r",stdin)
#define fout freopen("a.txt","w",stdout)
#define fio ios::sync_with_stdio(false);cin.tie(0)
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline void sub(ll &a,ll b){a-=b;if(a<0)a+=mod;}
inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;}
template<typename T>inline T const& MAX(T const &a,T const &b){return a>b?a:b;}
template<typename T>inline T const& MIN(T const &a,T const &b){return a<b?a:b;}
inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
inline ll qp(ll a,ll b,ll c){ll ans=1;while(b){if(b&1)ans=ans*a%c;a=a*a%c,b>>=1;}return ans;}
using namespace std;
const ull ba=233;
const db eps=1e-5;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=100000+10,maxn=1000000+10,inf=0x3f3f3f3f;
ll a[N],mi[N<<2],lazy[N<<2];
int son[N],dep[N],sz[N],fa[N][20],top[N],id[N],l[N],r[N];
int head[N],cnt,res;
struct edge{int to,Next;}e[N<<1];
void add(int u,int v){e[cnt].to=v,e[cnt].Next=head[u];head[u]=cnt++;}
void init(){cnt=0;memset(head,-1,sizeof head);memset(son,-1,sizeof son);}
void dfs1(int u,int f,int de)
{
fa[u][0]=f;sz[u]=1;dep[u]=de;
for(int i=head[u];~i;i=e[i].Next)
{
int x=e[i].to;
if(x!=f)
{
dfs1(x,u,de+1);sz[u]+=sz[x];
if(son[u]==-1||sz[x]>sz[son[u]])son[u]=x;
}
}
}
void dfs2(int u,int f,int tp)
{
top[u]=tp;l[u]=++res;id[res]=u;
if(son[u]!=-1)dfs2(son[u],u,tp);
for(int i=head[u];~i;i=e[i].Next)
{
int x=e[i].to;
if(x!=f&&x!=son[u])dfs2(x,u,x);
}
r[u]=res;
}
void pushdown(int rt)
{
if(lazy[rt])
{
mi[rt<<1]=mi[rt<<1|1]=lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
lazy[rt]=0;
}
}
void build(int l,int r,int rt)
{
if(l==r){mi[rt]=a[id[l]];return ;}
int m=(l+r)>>1;
build(ls);build(rs);
mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
void update(int L,int R,ll v,int l,int r,int rt)
{
if(L<=l&&r<=R){mi[rt]=lazy[rt]=v;return ;}
pushdown(rt);
int m=(l+r)>>1;
if(L<=m)update(L,R,v,ls);
if(m<R)update(L,R,v,rs);
mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
void change(int a,int b,ll c)
{
int f1=top[a],f2=top[b];
while(f1!=f2)
{
if(dep[f1]<dep[f2])swap(f1,f2),swap(a,b);
update(l[f1],l[a],c,1,res,1);
a=fa[f1][0],f1=top[a];
}
if(dep[a]>dep[b])swap(a,b);
update(l[a],l[b],c,1,res,1);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)return mi[rt];
pushdown(rt);
int m=(l+r)>>1;ll ans=INF;
if(L<=m)ans=min(ans,query(L,R,ls));
if(m<R)ans=min(ans,query(L,R,rs));
return ans;
}
int lca(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
for(int i=19;i>=0;i--)if(((dep[y]-dep[x])>>i)&1)y=fa[y][i];
if(x==y)return x;
for(int i=19;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main()
{
// fin;
int n,m;scanf("%d%d",&n,&m);
init();
for(int i=1;i<n;i++)
{
int a,b;scanf("%d%d",&a,&b);
add(a,b);add(b,a);
}
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
int root;scanf("%d",&root);
int rr=root;
dfs1(root,0,1);dfs2(root,0,root);
build(1,n,1);
for(int i=1;i<20;i++)for(int j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1];
while(m--)
{
int op,a,b;ll c;scanf("%d",&op);
if(op==1){scanf("%d",&a),rr=a;}
else if(op==2){scanf("%d%d%lld",&a,&b,&c);change(a,b,c);}
else
{
scanf("%d",&a);
if(a==rr)printf("%lld\n",mi[1]);
else if(lca(rr,a)!=a)printf("%lld\n",query(l[a],r[a],1,n,1));
else
{
int y=rr,x=dep[a]+1;
for(int i=19;i>=0;i--)if(((dep[y]-x)>>i)&1)y=fa[y][i];
ll ans=INF;
if(l[y]>1)ans=min(ans,query(1,l[y]-1,1,n,1));
if(r[y]<n)ans=min(ans,query(r[y]+1,n,1,n,1));
printf("%lld\n",ans);
}
}
}
return 0;
}
/********************
5 2
4 2
2 5
5 3
3 1
490 387 927 484 130
3
1 2
3 3
********************/