题目大意
给定一个n个节点的有根树,每个节点有一个权值s[i],且有颜色(最初全是白色)。有m次操作,分两种:
1. 把一个节点染黑。
2. 询问一个节点x,枚举每个黑色节点y,得到lca(x,y)=z,求所有可能的z中最大的权值
n≤100000 m≤200000
分析
一个思路:
维护f[i]表示以i节点为根的子树中有多少个节点,当询问节点x的时候,暴力枚举它和它的所有祖先,如果枚举到一个i,它的f[x]和f[father(i)]不相等,那么一定存在一个黑色节点和x的lca为father(i)。(这个比较显然)
那么修改就是暴力给x和它的父亲全部f[i]++
观察这个过程,如果对于一个节点x,它第一次f[father(x)]>f[x],那么以后就一定会保持这个状态。那么一个算法流程出来了:
修改操作时,首先给它的子树的答案与s[x]取max,然后暴力往上跑,跑到一个节点x,给father(x)子树中除了x这个子树外的所有节点答案与s[x]取max。然后如果节点father(x)被访问过了,就表示f[father(x)]>f[x],就可以不继续往上跑了。
搞出dfn,然后线段树修改+查询。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=100005,M=200005,T=262200;
typedef long long LL;
int n,m,tot,h[N],e[M],nxt[M],s[N],fa[N],Size[N],dfn[N],t[T];
bool tu_color[N],visit[N];
char c;
int read()
{
for (c=getchar();c<'0' || c>'9';c=getchar());
int x=c-48;
for (c=getchar();c>='0' && c<='9';c=getchar()) x=x*10+c-48;
return x;
}
void add(int x,int y)
{
e[++tot]=y; nxt[tot]=h[x]; h[x]=tot;
}
void dfs(int x)
{
dfn[x]=++tot;
for (int i=h[x];i;i=nxt[i]) if (e[i]!=fa[x])
{
fa[e[i]]=x;
dfs(e[i]);
Size[x]+=Size[e[i]]+1;
}
}
void push_down(int x)
{
if (t[x]>0)
{
t[x<<1]=max(t[x<<1],t[x]);
t[x<<1|1]=max(t[x<<1|1],t[x]);
t[x]=0;
}
}
void change(int l,int r,int a,int b,int v,int x)
{
if (l==a && r==b)
{
t[x]=max(t[x],v);
return;
}
push_down(x);
int mid=l+r>>1;
if (b<=mid) change(l,mid,a,b,v,x<<1);
else if (a>mid) change(mid+1,r,a,b,v,x<<1|1);
else
{
change(l,mid,a,mid,v,x<<1); change(mid+1,r,mid+1,b,v,x<<1|1);
}
}
int query(int l,int r,int g,int x)
{
if (l==r) return t[x];
push_down(x);
int mid=l+r>>1;
if (g<=mid) return query(l,mid,g,x<<1);
return query(mid+1,r,g,x<<1|1);
}
int main()
{
freopen("lca.in","r",stdin); freopen("lca.out","w",stdout);
n=read(); m=read();
for (int i=1;i<=n;i++) s[i]=read();
for (int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y); add(y,x);
}
tot=0;
dfs(1);
visit[1]=1;
memset(t,255,sizeof(t));
while (m--)
{
for (c=getchar();c!='Q' && c!='M';c=getchar());
if (c=='M')
{
int x=read();
if (tu_color[x]) continue;
tu_color[x]=1;
change(1,n,dfn[x],dfn[x]+Size[x],s[x],1);
for (;!visit[x];x=fa[x])
{
visit[x]=1;
if (dfn[fa[x]]<dfn[x]) change(1,n,dfn[fa[x]],dfn[x]-1,s[fa[x]],1);
if (dfn[x]+Size[x]<dfn[fa[x]]+Size[fa[x]])
change(1,n,dfn[x]+Size[x]+1,dfn[fa[x]]+Size[fa[x]],s[fa[x]],1);
}
}else
{
int x=read();
printf("%d\n",query(1,n,dfn[x],1));
}
}
fclose(stdin); fclose(stdout);
return 0;
}