题解 最近公共祖先

传送门

考场上坚持认为树剖可做,于是几乎爆零
别一直坚持一个思路!就算这个思路很可能是对的但自己不会写也要及时换思路!

但正解思路跟考场上想的思路真的很像,连开的数组都一样
考虑一个点被染黑时可能更新哪些白点的答案
开一个bool two[]和一个int son[],两个标记不共存,上翻修改
然后我们需要对一棵子树整体取min
可以按dfs序建一棵线段树,标记永久化
尤其注意id[u]+siz[u]id[fa]+siz[fa]-1的边界即可

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long 
//#define int long long 

inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int head[N], size, val[N];
bool black[N];
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;}

namespace force{
	int dep[N], lg[N], fa[N][25], sta[N], top;
	void dfs(int u, int pa) {
		for (int i=1; i<24; ++i) 
			if (dep[u]>=(1<<i)) fa[u][i]=fa[fa[u][i-1]][i-1];
			else break;
		for (int i=head[u],v; i; i=e[i].next) {
			v = e[i].to;
			if (v!=pa) dep[v]=dep[u]+1, fa[v][0]=u, dfs(v, u);
		}
	}
	int lca(int a, int b) {
		if (dep[a]<dep[b]) swap(a, b);
		while (dep[a]>dep[b]) a=fa[a][lg[dep[a]-dep[b]]-1];
		if (a==b) return a;
		for (int i=lg[dep[a]]-1; ~i; --i) 
			if (fa[a][i]!=fa[b][i]) 
				a=fa[a][i], b=fa[b][i];
		return fa[a][0];
	}
	void solve() {
		char t[20];
		for (int i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
		dep[1]=1;
		dfs(1, 0);
		for (int i=1,u,ans; i<=m; ++i) {
			scanf("%s%d", t, &u);
			if (*t=='M') {
				if (!black[u]) {black[u]=1; sta[++top]=u;}
			}
			else {
				ans=-1;
				for (int j=1; j<=top; ++j) 
					ans=max(ans, val[lca(u, sta[j])]);
				printf("%d\n", ans);
			}
		}
		exit(0);
	}
}

namespace task1{
	bool two[N];
	int son[N], fa[N];
	void dfs(int u, int pa) {
		for (int i=head[u],v; i; i=e[i].next) {
			v = e[i].to;
			if (v!=pa) fa[v]=u, dfs(v, u);
		}
	}
	void solve() {
		char t[20];
		dfs(1, 0);
		for (int i=1,u,ans; i<=m; ++i) {
			scanf("%s%d", t, &u);
			if (*t=='M') {
				if (!black[u]) {
					black[u]=1;
					int now=fa[u], it=u;
					//cout<<"upd "<<u<<endl;
					while (now) {
						//cout<<"now: "<<now<<' '<<it<<endl;
						if (two[now] || son[now]==it) break;
						else if (!son[now]) son[now]=it;
						else two[now]=1;
						it=now, now=fa[now];
					}
				}
			}
			else {
				ans=-1;
				if (son[u] || black[u]) ans=max(ans, val[u]);
				int now=fa[u], it=u;
				//cout<<"query "<<u<<endl;
				while (now) {
					//cout<<"now: "<<now<<' '<<it<<endl;
					if (two[now] || (son[now]&&son[now]!=it) || black[now]) ans=max(ans, val[now]);
					it=now, now=fa[now];
				}
				printf("%d\n", ans);
			}
		}
		exit(0);
	}
}

namespace task{
	bool two[N];
	int siz[N], id[N], rk[N], son[N], fa[N], tot;
	int tl[N<<2], tr[N<<2], maxn[N<<2];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define maxn(p) maxn[p]
	void build(int p, int l, int r) {
		//cout<<"build "<<p<<' '<<l<<' '<<r<<endl;
		tl(p)=l; tr(p)=r;
		if (l==r) return ;
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
	}
	void upd(int p, int l, int r, int dat) {
		//scout<<"upd "<<p<<' '<<tl(p)<<' '<<tr(p)<<' '<<l<<' '<<r<<' '<<dat<<endl;
		if (l<=tl(p) && r>=tr(p)) {maxn(p)=max(maxn(p), dat); return ;}
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r, dat);
		if (r>mid) upd(p<<1|1, l, r, dat);
	}
	int query(int p, int pos) {
		if (tl(p)==tr(p)) return maxn(p);
		int mid=(tl(p)+tr(p))>>1, ans=maxn(p);
		if (pos<=mid) ans=max(ans, query(p<<1, pos));
		else ans=max(ans, query(p<<1|1, pos));
		return ans;
	}
	void dfs(int u, int pa) {
		siz[u]=1;
		id[u]=++tot;
		rk[tot]=u;
		for (int i=head[u],v; i; i=e[i].next) {
			v = e[i].to;
			if (v!=pa) fa[v]=u, dfs(v, u), siz[u]+=siz[v];
		}
	}
	void solve() {
		char t[20];
		memset(maxn, -1, sizeof(maxn));
		dfs(1, 0);
		build(1, 1, n);
		for (int i=1,x; i<=m; ++i) {
			scanf("%s%d", t, &x);
			if (*t=='M') {
				upd(1, id[x], id[x]+siz[x]-1, val[x]);
				int now=fa[x], u=x;
				while (now) {
					if (two[now] || son[now]==u) break;
					else if (!son[now]) {
						son[now]=u;
						upd(1, id[now], id[u]-1, val[now]);
						if (id[u]+siz[u]<=id[now]+siz[now]-1) upd(1, id[u]+siz[u], id[now]+siz[now]-1, val[now]);
					}
					else two[now]=1, upd(1, id[now], id[now]+siz[now]-1, val[now]);
					u=now, now=fa[now];
				}
			}
			else printf("%d\n", query(1, id[x]));
		}
		exit(0);
	}
}

signed main()
{
	n=read(); m=read();
	for (int i=1; i<=n; ++i) val[i]=read();
	for (int i=1,u,v; i<n; ++i) {
		u=read(); v=read(); 
		add(u, v); add(v, u);
	}
	//force::solve();
	task::solve();
	
	return 0;
}
posted @ 2021-08-03 21:45  Administrator-09  阅读(30)  评论(3编辑  收藏  举报