遥远的国度(树链剖分)

原题洛谷搜索

分析

原题翻译一下:给你一棵N-1条边,N个点的树,每个点有权值,并给你指定了一个根节点。然后有三类操作:一是把根节点换成i,二是把x到y的路径上的所有点权值改成v,三是查询以x为根的子树里的最小权值。

看到树上区间查询修改,自然想到运用树剖(其实是学到这里)。这个题和树剖模板也就多了一个换根。因此只分析换根有关。

第一个操作直接输入根即可。第二个操作还是以最初给定的的根为准区间修改。

第三个操作:设现在的根为rootnow,查询的是u的子树

1,rootnow=u,那么就是整棵树里找最小值,直接输出val[1]。

2,若LCA(u,rootnow)!=u,画图可知,u的子树没有影响,直接查询即可。

3,LCA(u,rootnow)=u,此时u的子树需要剔除rootnow所在的那一棵,画图理解(将就看吧)

可以得知,要找到rootnow到u上,离u最近的那个儿子chi,于是可以用倍增求出。

求出儿子之后,因为这个儿子chi的DFS序范围是dfs_pos[chi]~dfs_pos[chi]+size[chi]-1,而我们只需跳过这一段,所以把整个DFS序分成两截查询。

由于rootnow是u的后代,所以rootnow成根之后删掉上述子树,其余的一定都在u的子树里,画图可知。

提醒一个坑点:线段树初值

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100005;
const int INF=2000000000;
int N,M,rootnow,root,np2=0,dfs_clock=0,a[MAXN],b[MAXN],last[MAXN],fa[MAXN][20];
int dep[MAXN],size[MAXN],top_node[MAXN],dfs_pos[MAXN],big_son[MAXN];
int np=0,rt=0,val[MAXN*2],lc[MAXN*2],rc[MAXN*2],change[MAXN*2];
struct edge{int to,pre;}E[MAXN*2];

void addedge(int u,int v)
{
	E[++np2]=(edge){v,last[u]};
	last[u]=np2;
}

char c;
void scan(int &x)
{
	for(c=getchar();c<'0'||c>'9';c=getchar());
	for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
}

char num[20];int ct;
void print(int x)
{
	ct=0;
	if(!x) num[ct++]='0';
	while(x) num[ct++]=x%10+'0',x/=10;
	while(ct--) putchar(num[ct]);
	putchar('\n');
}

//-------------------------------------
void DFS1(int i,int f,int d)
{
	fa[i][0]=f; dep[i]=d; size[i]=1;
	for(int p=1;p<=18;p++)
	{
		int j=fa[i][p-1];
		fa[i][p]=fa[j][p-1];
	}
	for(int p=last[i];p;p=E[p].pre)
	{
		int j=E[p].to;
		if(j==f) continue;
		DFS1(j,i,d+1);
		size[i]+=size[j];
		if(size[j]>size[big_son[i]]) big_son[i]=j;
	}
}

void DFS2(int i,int top)
{
	top_node[i]=top;
	dfs_pos[i]=++dfs_clock;
	b[dfs_clock]=a[i];
	if(!big_son[i]) return;
	DFS2(big_son[i],top);
	for(int p=last[i];p;p=E[p].pre)
	{
		int j=E[p].to;
		if(j==fa[i][0]||j==big_son[i]) continue;
		DFS2(j,j);
	}
}
//-------------------------------------------
void pushup(int now) {val[now]=min(val[lc[now]],val[rc[now]]);}

void build(int &now,int L,int R)
{
	if(!now) now=++np;
	if(L==R)
	{
		val[now]=b[L];
		return;
	}
	int mid=(L+R)/2;
	build(lc[now],L,mid);
	build(rc[now],mid+1,R);
	pushup(now);
}

void pushdown(int now)
{
	if(!change[now]) return;
	val[lc[now]]=val[rc[now]]=change[lc[now]]=change[rc[now]]=change[now];
	change[now]=0;
}

void update(int now,int L,int R,int i,int j,int d)
{
	if(i<=L&&R<=j)
	{
		val[now]=d;
		change[now]=d;
		return;
	}
	pushdown(now);
	int mid=(L+R)/2;
	if(i<=mid) update(lc[now],L,mid,i,j,d);
	if(mid<j) update(rc[now],mid+1,R,i,j,d);
	pushup(now);
}

int ques(int now,int L,int R,int i,int j)
{
	if(i<=L&&R<=j) return val[now];
	pushdown(now);
	int mid=(L+R)/2,ret=INF;
	if(i<=mid) ret=min(ret,ques(lc[now],L,mid,i,j));
	if(mid<j) ret=min(ret,ques(rc[now],mid+1,R,i,j));
	pushup(now); return ret;
}
//------------------------------------
int get_lca(int u,int v)
{
	if(dep[u]<dep[v]) swap(u,v);
	int t=dep[u]-dep[v];
	for(int i=18;i>=0;i--) if(t&(1<<i)) u=fa[u][i];
	if(u==v) return u;
	for(int i=18;i>=0;i--) if(fa[u][i]!=fa[v][i])
	{
		u=fa[u][i];
		v=fa[v][i];
	}
	return fa[u][0];
}

int get_chi(int u,int dis)
{
	for(int i=18;i>=0;i--) if(dis&(1<<i)) u=fa[u][i];
	return u;
}

void uprange(int u,int v,int w)
{
	while(top_node[u]!=top_node[v])
	{
		if(dep[top_node[u]]<dep[top_node[v]]) swap(u,v);
		update(rt,1,N,dfs_pos[top_node[u]],dfs_pos[u],w);
		u=fa[top_node[u]][0];
	}
	if(dep[u]>dep[v]) swap(u,v);
	update(rt,1,N,dfs_pos[u],dfs_pos[v],w);
}

int qtree(int u)
{
	if(rootnow==u) return val[rt];
	int lca=get_lca(u,rootnow);
	if(lca!=u) return ques(rt,1,N,dfs_pos[u],dfs_pos[u]+size[u]-1);
	else
	{
		int d=dep[rootnow]-dep[u]-1;
		int chi=get_chi(rootnow,d);
		return min(ques(rt,1,N,1,dfs_pos[chi]-1),ques(rt,1,N,dfs_pos[chi]+size[chi],N));
	}
}

int main()
{
	scan(N); scan(M);
	int i,u,v,w,op;
	for(i=1;i<N;i++)
	{
		scan(u);scan(v);
		addedge(u,v);
		addedge(v,u);
	}
	for(i=1;i<=N;i++) scan(a[i]);
	scan(root); rootnow=root;
	DFS1(root,0,1); DFS2(root,root); 
	for(i=0;i<=N*2+5;i++) val[i]=INF;
	build(rt,1,N);
	while(M--)
	{
		scan(op);
		if(op==1) scan(rootnow);
		else if(op==2)
		{
			scan(u);scan(v);scan(w);
			uprange(u,v,w);
		}
		else
		{
			scan(u);
			print(qtree(u));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/WWWengine/article/details/81612957