3083: 遥远的国度
Time Limit: 10 Sec Memory Limit: 1280 MB
Submit: 2022 Solved: 496
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。
Source
zhonghaoxi提供
代码地址:http://paste.ubuntu.com/15308032/
一开始读入的根没有什么卵用。。
操作1:直接换根。。
操作2:修改u到v的路径权值。。
操作3:分类讨论
①root=x,直接查询整棵树的最小值。。
②lca(root,x)!=x,直接查询x的子树的最小值。。
③lca(root,x)=x,先倍增找到与lca最近的点,然后查询补集的最小值。。
这道题我调了一周。。而且还是在Claris神犇的帮助下。。
首先说一下RE和WA的错误点:
①无论是求最小值,还是区间修改、单点修改、区间查询,都要update和pushdown。。
②pushdown的时候要判断是否有标记,若没有则不能pushdown。。
③未考虑到x>y时的情况。。
④写区间修改等操作的时候,一定要清楚传的变量是什么。。
以上问题我纠结了一周。。(有间隔)
感谢Claris神犇。。
附上本蒟蒻的代码:
#include
#include
#include
#include
using namespace std;
int delta[400001]={0},n,m,cnt,sz,a[200001],mx[200001],h[200001],father[200001][17],v[200001],deep[200001],size[200001],pos[200001],belong[200001];
bool vis[200001];
struct data
{
int to,next;
};
data edge[200001];
struct kx
{
int value;
};
kx node[400001];
int read()
{
int w=0,c=1;
char ch=getchar();
while (ch<'0' || ch>'9')
{
if (ch=='-')
c=-1;
ch=getchar();
}
while (ch>='0' && ch<='9')
{
w=w*10+ch-'0';
ch=getchar();
}
return w*c;
}
void add(int u,int v)
{
cnt++;
edge[cnt].next=h[u];
h[u]=cnt;
edge[cnt].to=v;
}
void dfs1(int x)
{
int i;
size[x]=1;
vis[x]=true;
for (i=1;i<=16;i++)
{
if (deep[x]<(1<break;
father[x][i]=father[father[x][i-1]][i-1];
}
for (i=h[x];i;i=edge[i].next)
{
if (vis[edge[i].to])
continue;
deep[edge[i].to]=deep[x]+1;
father[edge[i].to][0]=x;
dfs1(edge[i].to);
size[x]+=size[edge[i].to];
mx[x]=max(mx[x],mx[edge[i].to]);
}
}
void dfs2(int x,int chain)
{
int k=0,i;
sz++;
pos[x]=mx[x]=sz;
belong[x]=chain;
for (i=h[x];i;i=edge[i].next)
if (deep[edge[i].to]>deep[x] && size[edge[i].to]>size[k])
k=edge[i].to;
if (k==0)
return;
dfs2(k,chain);
mx[x]=max(mx[x],mx[k]);
for (i=h[x];i;i=edge[i].next)
if (deep[edge[i].to]>deep[x] && k!=edge[i].to)
{
dfs2(edge[i].to,edge[i].to);
mx[x]=max(mx[x],mx[edge[i].to]);
}
}
void update(int s)
{
node[s].value=min(node[s*2].value,node[s*2+1].value);
}
void build(int s,int l,int r)
{
if (l==r)
return;
build(s*2,l,(l+r)/2);
build(s*2+1,(l+r)/2+1,r);
}
void paint(int s,int z,int l,int r)
{
node[s].value=z;
delta[s]=z;
}
void pushdown(int s,int l,int r)
{
int mid=(l+r)/2;
paint(s*2,delta[s],l,mid);
paint(s*2+1,delta[s],mid+1,r);
delta[s]=0;
}
void change(int s,int l,int r,int x,int y)
{
int mid=(l+r)/2;
if (l==x && l==r)
{
node[s].value=y;
return;
}
if (delta[s])
pushdown(s,l,r);
if (x<=mid)
change(s*2,l,mid,x,y);
else
change(s*2+1,mid+1,r,x,y);
update(s);
}
void insert(int s,int l,int r,int x,int y,int z)
{
int mid=(l+r)/2;
if (x<=l && y>=r)
{
paint(s,z,l,r);
return;
}
if (delta[s])
pushdown(s,l,r);
if (x<=mid)
insert(s*2,l,mid,x,y,z);
if (y>mid)
insert(s*2+1,mid+1,r,x,y,z);
update(s);
}
void solveinsert(int x,int y,int z)
{
for (;belong[x]!=belong[y];x=father[belong[x]][0])
{
if (deep[belong[x]]y]])
swap(x,y);
insert(1,1,n,pos[belong[x]],pos[x],z);
}
if (deep[x]y])
swap(x,y);
insert(1,1,n,pos[y],pos[x],z);
}
int querymin(int s,int l,int r,int x,int y)
{
int mid=(l+r)/2,ans;
if (x>y)
return INT_MAX;
if (x<=l && y>=r)
return node[s].value;
if (delta[s])
pushdown(s,l,r);
if (x<=mid)
ans=querymin(s*2,l,mid,x,y);
else
ans=INT_MAX;
if (y>mid)
ans=min(querymin(s*2+1,mid+1,r,x,y),ans);
update(s);
return ans;
}
int lca(int x,int y)
{
int i,t;
if (deep[x]y])
swap(x,y);
t=deep[x]-deep[y];
for (i=16;i>=0;i--)
if (t&(1<x=father[x][i];
for (i=16;i>=0;i--)
if (father[x][i]!=father[y][i])
{
x=father[x][i];
y=father[y][i];
}
if (x==y)
return x;
else
return father[x][0];
}
int main()
{
/*freopen("country.in","r",stdin);
freopen("country.out","w",stdout);*/
int i,u,v,ask,x,y,z,root,t,hkx,depth;
n=read(),m=read();
for (i=1;i<=n-1;i++)
{
u=read(),v=read();
add(u,v),add(v,u);
}
for (i=1;i<=n;i++)
a[i]=read();
dfs1(1);
dfs2(1,1);
build(1,1,n);
for (i=1;i<=n;i++)
change(1,1,n,pos[i],a[i]);
root=read();
for (i=1;i<=m;i++)
{
ask=read(),x=read();
if (ask==1)
root=x;
if (ask==2)
{
y=read(),z=read();
solveinsert(x,y,z);
}
if (ask==3)
{
t=lca(root,x);
if (root==x)
printf("%d\n",querymin(1,1,n,1,n));
else
if (t!=x)
printf("%d\n",querymin(1,1,n,pos[x],mx[x]));
else
if (t==x)
{
hkx=root;
depth=deep[root]-deep[x]-1;
for (int j=16;j>=0;j--)
if (depth&(1<printf("%d\n",min(querymin(1,1,n,1,pos[hkx]-1),querymin(1,1,n,mx[hkx]+1,n)));
}
}
}
/*fclose(stdin);
fclose(stdout);*/
return 0;
}