WOJ 3784 【模板】树链剖分换根

描述

给定一棵大小为 n 的有根点权树,支持以下操作:

? 换根

? 修改点权

? 查询子树最小值

输入

第一行两个整数 n, Q ,分别表示树的大小和操作数。

接下来n行,每行两个整数f,v,第i+1行的两个数表示点i的父亲和点i的权。保

证f < i。如 果f = 0,那么i为根。输入数据保证只有i = 1时,f = 0。

接下来 m 行,为以下格式中的一种:

? V x y表示把点x的权改为y

? E x 表示把有根树的根改为点 x

? Q x 表示查询点 x 的子树最小值

输出

对于每个 Q ,输出子树最小值。

样例输入

3 7
0 1
1 2
1 3
Q 1
V 1 6
Q 1
V 2 5
Q 1
V 3 4
Q 1

样例输出

1
2
3
4

提示

对于 100% 的数据:n, Q ≤ 10^5。

题解

对于换根操作,如果询问点为\(root\),相当于整棵子树的答案
若询问点不为\(root\)祖先,则相当于以\(1\)为根的子树
若询问点是\(root\)的祖先,那么对于点\(y\)的询问相当于询问除去含\(root\)的子树的最小值,\(dfs\)序则为序列的两段
用树剖+线段树+LCA维护即可

代码

#include<bits/stdc++.h>
#define N 100005
#define inf 0x7fffffff
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (t[p].l+t[p].r>>1)
#define T pair<int,int>
#define mp make_pair
#define il inline
#define vo void
#define in read()
using namespace std;
inline int read()
{
    int data=0,w=1;char ch=getchar();
    while(ch!=‘-‘&& (ch<‘0‘||ch>‘9‘)) ch=getchar();
    if(ch==‘-‘) w=-1,ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘) data=(data<<3)+(data<<1)+ch-‘0‘,ch=getchar();
    return data*w;
}
int n,q;
vector<int> e[N];
int first[N],cnt;
il vo add(int s,int fa) {e[fa].push_back(s);}
int siz[N],hson[N],dep[N],fa[N];
int num[N],top[N],pred[N],idx;
int a[N],root=1;

il char gc()
{
	char c=getchar();
	while(c==‘ ‘||c==‘\n‘||c==‘\r‘)c=getchar();
	return c;
}

vo dfs1(int u)
{
	siz[u]=1;hson[u]=0;
	for(int i=0;i<e[u].size();i++)
	{
		int v=e[u][i];
		dep[v]=dep[u]+1;fa[v]=u;
		dfs1(v);
		siz[u]+=siz[v];
		if(siz[hson[u]]<siz[v]) hson[u]=v;
	}
}

vo dfs2(int u,int tp)
{
	int son;
	top[u]=tp;num[u]=++idx;pred[idx]=u;
	if(hson[u]) dfs2(hson[u],tp);
	for(int i=0;i<e[u].size();i++)
		if(hson[u]!=e[u][i])
			dfs2(e[u][i],e[u][i]);
}


struct tree{
	int l,r,minn;
}t[N<<2];

il vo pushup(int p){t[p].minn=min(t[lc].minn,t[rc].minn);}

il vo build(int p,int l,int r)
{
	t[p].l=l;t[p].r=r;
	if(l==r) {t[p].minn=a[pred[l]];return ;}
	build(lc,l,mid);build(rc,mid+1,r);
	pushup(p);
}

il vo update(int p,int pos,int v)
{
	if(t[p].l==t[p].r){t[p].minn=v;return ;}
	if(pos<=mid) update(lc,pos,v);
	else update(rc,pos,v);
	pushup(p);
}

il int query(int p,int ql,int qr)
{
	if(ql>t[p].r||qr<t[p].l) return inf;
	if(t[p].l>=ql&&t[p].r<=qr) return t[p].minn;
	int ret=inf;
	if(ql<=mid) ret=min(query(lc,ql,qr),ret);
	if(qr>mid) ret=min(query(rc,ql,qr),ret);
	return ret;
}

il T lca(int x,int y)
{
	int ch=0;int tx=top[x],ty=top[y];
	while(tx!=ty)
	{
		if(dep[tx]<dep[ty]) swap(x,y),swap(tx,ty);
		if(fa[tx]==y) ch=tx;
		x=fa[tx],tx=top[x];
	}
	if(dep[x]>dep[y]) swap(x,y);
	return mp(x,ch?ch:hson[x]);
}

il int qm(int x)
{
	if(x==root) return t[1].minn;
	T Lca=lca(x,root);int ch=Lca.second;
	if(Lca.first!=x) return query(1,num[x],num[x]+siz[x]-1);
	else return min(query(1,1,num[ch]-1),query(1,num[ch]+siz[ch],n));
}


int main()
{
	n=in,q=in;
	for(int i=1;i<=n;i++) add(i,in),a[i]=in;
	dfs1(1); dfs2(1,1); build(1,1,n);
	int u=0;
	while(q--)
	{
		switch(gc())
		{
			case ‘V‘:u=in;update(1,num[u],in);break;
			case ‘E‘:root=read();break;
			case ‘Q‘:printf("%d\n",qm(in));break;
		}
	}
	return 0;
}

WOJ 3784 【模板】树链剖分换根

上一篇:xml文件报错:The reference to entity "characterEncoding" must end with the ';' delimiter.


下一篇:flink core 流处理,批处理