3083: 遥远的国度

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;
}


你可能感兴趣的:(3083: 遥远的国度)