3083: 遥远的国度
Time Limit: 10 Sec
Memory Limit: 1280 MB
Submit: 2118
Solved: 516
[ Submit][ Status][ Discuss]
Description
描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。
问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。
Input
第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。
Output
对于每个opt=3的操作,输出一行代表对应子树的最小点权值。
Sample Input
3 7
1 2
1 3
1 2 3
1
3 1
2 1 1 6
3 1
2 2 2 5
3 1
2 3 3 4
3 1
Sample Output
1
2
3
4
提示
对于20%的数据,n<=1000 m<=1000。
对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。
HINT
Source
题解:
题目分析转载自:http://blog.csdn.net/lcomyn/article/details/45718295
BZOJ 3083 遥远的国度
这题的与 HAOI 2015T2 的不同点在于其有换根操作,但按照普通的思路我们可以发现,换根之后树的形态会有改变,每个节点的子树会发生改变,所以我们来分类讨论。
修改链的操作不会发生改变,现在只考虑子树minn。为了方便,我们定义现在的换的“根节点”为root(但实际上树的根节点为1),子树根为x,黑圈标明查询范围;
情况一 x=root,很显然此时应当查询整棵树。
情况二 lca(root,x)!=x ,此时直接查询x的子树即可,与换根无关。
情况三,lca(root,x)=x,此时我们应当查询与x相邻的节点中与root最近的点v在整棵树中的补集
可以发现v一定在root到x的链上,且一定是x在这条链上的儿子,倍增法可以求得v
总之就是dfs序+树链剖分,dfs序主要是用来记录子树的范围
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int m,n,next[200100],point[100100],v[200100],pos[100100],belong[100100];
int val[100100],tot,id;
int fa[100100][20],mi[20],deep[100100],size[100100];
int l[100100],r[100100],sz,root;
int tm[500100],vl[100100],delta[500100];
const int inf=2147213647;
void add(int x,int y)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void build(int x,int f,int depth)
{
deep[x]=depth; size[x]=1;
for (int i=1;i<=17;i++)
{
if (deep[x]-mi[i]<0) break;
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for (int i=point[x];i;i=next[i])
if (v[i]!=f)
{
fa[v[i]][0]=x;
build(v[i],x,depth+1);
size[x]+=size[v[i]];
}
}
void dfs(int x,int chain)
{
belong[x]=chain;
pos[x]=++sz;
vl[sz]=val[x];
l[x]=sz;
int k=0;
for (int i=point[x];i;i=next[i])
if (size[v[i]]>size[k]&&v[i]!=fa[x][0])
k=v[i];
r[x]=sz;
if (k==0) return;
dfs(k,chain);
for (int i=point[x];i;i=next[i])
if (v[i]!=k&&v[i]!=fa[x][0])
dfs(v[i],v[i]);
r[x]=sz;
}
void pushdown(int x)
{
if (delta[x])
{
tm[x<<1]=delta[x];
delta[x<<1]=delta[x];
tm[x<<1|1]=delta[x];
delta[x<<1|1]=delta[x];
delta[x]=0;
}
}
void update(int x)
{
tm[x]=min(tm[x<<1],tm[x<<1|1]);
}
void buildtree(int now,int l,int r)
{
if (l==r)
{
tm[now]=vl[l];
return;
}
int mid=(l+r)/2;
buildtree(now<<1,l,mid);
buildtree((now<<1)+1,mid+1,r);
update(now);
}
int qjmin(int now,int l,int r,int lx,int rx)
{
if (l>=lx&&r<=rx)
return tm[now];
int mid=(l+r)/2;
pushdown(now);
int ans=inf;
if (lx<=mid)
ans=min(ans,qjmin(now<<1,l,mid,lx,rx));
if (rx>mid)
ans=min(ans,qjmin(now<<1|1,mid+1,r,lx,rx));
return ans;
}
void qjchange(int now,int l,int r,int lx,int rx,int x)
{
if (l>=lx&&r<=rx)
{
delta[now]=x;
tm[now]=x;
return;
}
int mid=(l+r)/2;
pushdown(now);
if (lx<=mid)
qjchange(now<<1,l,mid,lx,rx,x);
if (rx>mid)
qjchange(now<<1|1,mid+1,r,lx,rx,x);
update(now);
}
int lca(int x,int y)
{
if (deep[x]<deep[y])
swap(x,y);
int k=deep[x]-deep[y];
for (int i=0;i<=17;i++)
if (k>>i&1)
x=fa[x][i];
if (x==y) return x;
for (int i=17;i>=0;i--)
if (fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void solve(int l,int r,int x)
{
while (belong[l]!=belong[r])
{
if (deep[belong[l]]<deep[belong[r]]) swap(l,r);
qjchange(1,1,n,pos[belong[l]],pos[l],x);
l=fa[belong[l]][0];
}
if (deep[l]>deep[r]) swap(l,r);
qjchange(1,1,n,pos[l],pos[r],x);
}
int js(int x,int f,int cha)
{
for (int i=0;i<=17;i++)
if (cha>>i&1)
x=fa[x][i];
return x;
}
void work(int x)
{
int rootx=root; int xx=x;
if (xx==rootx)
printf("%d\n",qjmin(1,1,n,1,n));
else
if (lca(xx,rootx)!=xx)
printf("%d\n",qjmin(1,1,n,l[xx],r[xx]));
else
{
int mb=js(rootx,xx,deep[rootx]-deep[xx]-1);
int ans=inf;
if (l[mb]>1)
ans=min(ans,qjmin(1,1,n,1,l[mb]-1));
if (r[mb]<n)
ans=min(ans,qjmin(1,1,n,r[mb]+1,n));
printf("%d\n",ans);
}
}
int main()
{
scanf("%d%d",&n,&m);
mi[0]=1;
for (int i=1;i<=17;i++)
mi[i]=mi[i-1]*2;
for (int i=1;i<=n-1;i++)
{
int x,y; scanf("%d%d",&x,&y);
add(x,y);
}
for (int i=1;i<=n;i++)
scanf("%d",&val[i]);
scanf("%d",&root);
build(1,0,1);
dfs(1,1);
buildtree(1,1,n);
//for (int i=1;i<=n;i++)
//cout<<l[i]<<" "<<r[i]<<endl;
for (int i=1;i<=m;i++)
{
int num;scanf("%d",&num);
if (num==1)
{
int x; scanf("%d",&x);
root=x;
}
else
if (num==2)
{
int l,r,x; scanf("%d%d%d",&l,&r,&x);
solve(l,r,x);
}
else
if (num==3)
{
int x; scanf("%d",&x);
work(x);
}
}
}