3083: 遥远的国度
Time Limit: 10 Sec
Memory Limit: 1280 MB
Submit: 1847
Solved: 460
[ 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。
树链剖分+dfs序。。。
对于苟蒻来说也是难的可以啊。。。
首先注意int < 2^31 所以本题用unsigned int
对于dfs序。。。
先把这颗树剖分了吧!
确定所有重边后在dfs的时候优先走重边
这样就能将某段重路径上所有点放一起了!
于是就将路径问题转换为区间问题
将所有点建立一颗dfs序线段树
那么每次就可以进行区间查询?
对于每个更换root的命令。。
其实没什么影响
假设一开始的树根是1
现在更新了root
对于同一棵树的两个点
要么查询点是root的子树或root与查询点有公共祖先,那么查询不变
如果是root的祖先,显然除root所在那棵子树外其余都可以查询
画张图就一目了然!(胡说明明是学长教的。。)
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<ctime>
using namespace std;
const int maxn = 1E5 + 10;
typedef unsigned int LL;
int d_t = 0,n,m,i,j,root,L[maxn],qx,qy,qv,KEY,In[maxn],Out[maxn];
LL mark[maxn*20],c[maxn*20],Size[maxn],w[maxn],next[maxn],anc[maxn][20],D[maxn],head[maxn];
bool heavy[maxn],vis[maxn];
vector <LL> v[maxn];
void dfs(LL k)
{
Size[k] = 1;
LL tmp = 0;
for (LL l = 0; l < v[k].size(); l++) {
LL to = v[k][l];
if (vis[to]) continue;
vis[to] = 1;
anc[to][0] = k;
L[to] = L[k] + 1;
dfs(to);
if (Size[to] > tmp) tmp = Size[to],next[k] = to;
Size[k] += Size[to];
}
if (tmp) heavy[next[k]] = 1;
}
void dfs2(LL k)
{
In[k] = ++d_t; D[d_t] = k;
if (next[k] != -1) vis[next[k]] = 1,dfs2(next[k]);
for (LL l = 0; l < v[k].size(); l++) {
LL to = v[k][l];
if (vis[to]) continue;
vis[to] = 1;
dfs2(to);
}
Out[k] = d_t;
}
void build_tree(LL o,LL l,LL r)
{
if (l == r) {
c[o] = w[D[l]];
return;
}
LL mid = (l + r) >> 1;
build_tree(2*o,l,mid);
build_tree(2*o+1,mid+1,r);
c[o] = min(c[o*2],c[o*2+1]);
}
LL fa(LL qu,LL qv)
{
int log;
if (L[qu] < L[qv]) swap(qu,qv);
if (qu == qv) return qu;
for (log = 0; (L[qu] - (1<<log)) > 0; ++log);
for (j = log; j >= 0; j--)
if (L[qu] - (1<<j) > L[qv])
qu = anc[qu][j];
KEY = qu;
if (L[qu] != L[qv]) qu = anc[qu][0];
if (qu == qv) return qu;
for (j = log; j >= 0; j--)
if (anc[qu][j] != anc[qv][j])
qu = anc[qu][j],qv = anc[qv][j];
KEY = qu;
return anc[qu][0];
}
void push_down(LL o)
{
if (!mark[o]) return;
mark[2*o] = c[2*o] = mark[2*o+1] = c[2*o+1] = mark[o];
mark[o] = 0;
}
void modify(LL o,LL l,LL r,LL ql,LL qr)
{
if (ql <= l && r <= qr) {
c[o] = mark[o] = qv;
return;
}
push_down(o);
LL mid = (l+r) >> 1;
if (ql <= mid) modify(2*o,l,mid,ql,qr);
if (qr > mid) modify(2*o+1,mid+1,r,ql,qr);
c[o] = min(c[2*o],c[2*o+1]);
}
void Modify(LL x,LL y)
{
for (;;) {
if (x == y) {
modify(1,1,n,In[x],In[y]); return;
}
if (!heavy[y]) {
modify(1,1,n,In[y],In[y]); y = anc[y][0];
continue;
}
if (In[head[y]] >= In[x]) {
modify(1,1,n,In[head[y]],In[y]);
y = head[y];
if (x == y) return;
y = anc[y][0];
continue;
}
modify(1,1,n,In[x],In[y]); return;
}
}
LL s1(LL o,LL l,LL r,LL ql,LL qr)
{
if (ql <= l && r <= qr) return c[o];
push_down(o);
LL mid = (l+r) >> 1;
LL ret = 2E9;
if (ql <= mid) ret = min(ret,s1(2*o,l,mid,ql,qr));
if (qr > mid) ret = min(ret,s1(2*o+1,mid+1,r,ql,qr));
return ret;
}
int main()
{
#ifdef YZY
freopen("yzy.txt","r",stdin);
#endif
memset(anc,-1,sizeof(anc));
memset(next,-1,sizeof(next));
cin >> n >> m;
for (i = 1; i < n; i++) {
int x,y;
scanf("%d%d",&x,&y);
v[x].push_back(y); v[y].push_back(x);
}
for (i = 1; i <= n; i++) scanf("%u",&w[i]);
cin >> root;
L[1] = 1;
vis[1] = 1;
dfs(1);
for (j = 1; j < 20; j++)
for (i = 1; i <= n; i++)
anc[i][j] = anc[anc[i][j-1]][j-1];
memset(vis,0,sizeof(vis)); vis[1] = 1;
dfs2(1);
for (i = 1; i <= n; i++)
if (!heavy[i] && heavy[next[i]])
{
j = next[i];
while (j != -1) {
head[j] = i;
j = next[j];
}
}
build_tree(1,1,n);
while (m--) {
int opt; scanf("%d",&opt);
if (opt == 1) scanf("%u",&root);
if (opt == 2) {
scanf("%u%u%u",&qx,&qy,&qv);
LL qf = fa(qx,qy);
Modify(qf,qx); Modify(qf,qy);
}
if (opt == 3) {
scanf("%u",&qx);
if (qx == root) {
printf("%u\n",s1(1,1,n,1,n));
continue;
}
LL qf = fa(qx,root);
if (qf == root || qf != qx && qf != root) {
printf("%u\n",s1(1,1,n,In[qx],Out[qx]));
continue;
}
LL ans = s1(1,1,n,1,In[KEY]-1);
ans = min(ans,s1(1,1,n,Out[KEY]+1,n));
printf("%u\n",ans);
}
}
return 0;
}