NOIP 模擬 $29\; \rm 最近公共祖先$
阿新 • • 發佈:2021-08-06
題解
題解 \(by\;zj\varphi\)
首先考慮,如果將一個點修改成了黑點,那麼它能夠造成多少貢獻。
它先會對自己的子樹中的答案造成 \(w_x\) 的貢獻。
考慮祖先時,它會對不包括自己的子樹造成 \(w_fa\) 的貢獻。
那麼思路很顯然,直接暴力向上更新,若更新到一個祖先,它已經被更新過了,那麼更新完它之後直接退出就行,因為再向上,一定已經被更新過了。
實現的過程用在 \(\rm dfs\) 序上建線段樹即可。
這樣,每個點最多被更新一次,在詢問時,最多重複更新一個點,所以總複雜度為 \(\mathcal O\rm((n+m)logn)\)
Code
#include<bits/stdc++.h> #define ri register signed #define p(i) ++i namespace IO{ char buf[1<<21],*p1=buf,*p2=buf; #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++ struct nanfeng_stream{ template<typename T>inline nanfeng_stream &operator>>(T &x) { ri f=1;x=0;register char ch=getchar(); while(!isdigit(ch)) {if (ch=='-') x=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x=f?x:-x,*this; } }cin; } using IO::cin; namespace nanfeng{ #define FI FILE *IN #define FO FILE *OUT template<typename T>inline T cmax(T x,T y) {return x>y?x:y;} template<typename T>inline T cmin(T x,T y) {return x>y?y:x;} static const int N=1e5+7; int first[N],w[N],ld[N],rd[N],B[N],fa[N],t=1,n,m,tot,ol,nm; char s[N]; struct edge{int v,nxt;}e[N<<1]; inline void add(int u,int v) { e[t].v=v,e[t].nxt=first[u],first[u]=t++; e[t].v=u,e[t].nxt=first[v],first[v]=t++; } void dfs(int x,int f) { ld[x]=p(tot); for (ri i(first[x]),v;i;i=e[i].nxt) { if ((v=e[i].v)==f) continue; fa[v]=x; dfs(v,x); } rd[x]=tot; } struct Seg{ #define ls(x) (x<<1) #define rs(x) (x<<1|1) #define up(x) T[x].mx=cmax(T[ls(x)].mx,T[rs(x)].mx) struct segmenttree{int mx,lz;}T[N<<2]; inline void down(int x) { if (!T[x].lz) return; T[ls(x)].mx=cmax(T[ls(x)].mx,T[x].lz); T[rs(x)].mx=cmax(T[rs(x)].mx,T[x].lz); T[ls(x)].lz=cmax(T[ls(x)].lz,T[x].lz); T[rs(x)].lz=cmax(T[rs(x)].lz,T[x].lz); T[x].lz=0; } int query(int x,int p,int l,int r) { if (l==r) return T[x].mx; int mid(l+r>>1); down(x); if (p<=mid) return query(ls(x),p,l,mid); else return query(rs(x),p,mid+1,r); } void update(int x,int k,int l,int r,int lt,int rt) { if (l<=lt&&rt<=r) { T[x].mx=cmax(T[x].mx,k); return (void)(T[x].lz=cmax(T[x].lz,k)); } int mid(lt+rt>>1); down(x); if (l<=mid) update(ls(x),k,l,r,lt,mid); if (r>mid) update(rs(x),k,l,r,mid+1,rt); up(x); } }T; inline void update(int x) { ri nw=x,ns=x; T.update(1,w[x],ld[nw],rd[nw],1,n); B[nw]=1; nw=fa[nw]; while(nw) { for (ri i(first[nw]),v;i;i=e[i].nxt) { if ((v=e[i].v)==ns||v==fa[nw]) continue; T.update(1,w[nw],ld[v],rd[v],1,n); } if (B[nw]) return; T.update(1,w[nw],ld[nw],ld[nw],1,n); B[nw]=1; ns=fa[ns],nw=fa[nw]; } } inline int main() { //FI=freopen("nanfeng.in","r",stdin); //FO=freopen("nanfeng.out","w",stdout); cin >> n >> m; for (ri i(1);i<=n;p(i)) cin >> w[i]; for (ri i(1),u,v;i<n;p(i)) cin >> u >> v,add(u,v); dfs(1,0); for (ri i(1),v;i<=m;p(i)) { scanf("%s",s+1); cin >> v; if (s[1]=='Q') { if (!nm) puts("-1"); else printf("%d\n",T.query(1,ld[v],1,n)); } else p(nm),update(v); } return 0; } } int main() {return nanfeng::main();}