1 条题解
-
0
自动搬运
来自洛谷,原作者为

耳朵龙_
老师说不要看没用的东西,看来不能照镜子了搬运于
2025-08-24 22:58:58,当前版本为作者最后更新于2024-05-25 18:11:45,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
与字符集大小无关的 做法,狠狠爆标!
场上写的是时空 的长剖做法。若字符集较大可以先离散化,下面认为字符集大小为 。记 表示从 开始,走到 子树内任意一个叶子,能选出的开头为 的最长不降子序列长度(忽略 的限制)。枚举是否选择点 ,再枚举走向的子结点 ,有转移
$$f_{i,j}=\begin{cases}1+\max\limits_{v= c_i}^{|\Sigma|}\max\limits_uf_{u,v}&j=c_i\\\max\limits_uf_{u,j}&j\ne c_i\end{cases} $$用线段树合并维护第二维,可以 求出所有 值。设 。设 ,即必须选择 时的最长不降子序列长度。设点 的答案为 ,深度为 ,其子树内结点的集合为 。
求答案时,设 表示选择点 的符合题意的最长不降子序列长, 表示不选择点 的符合题意的最长不降子序列长,则 。将这两部分分开考虑。
枚举子序列的第一个点,有
$$b_i=\max_{u\in S_i,d_u\ge d_i+p_i}h_u=\max_{u\in S_i,d_u\ge d_i+p_i}g_u $$对于互为父子的点 ,有 ,因此,
设 表示 子树内所有深度为 的结点 其 的最大值, 即为 。 的维护是长链剖分的基本操作,不再赘述,计算出 后,这一部分的总时间复杂度为 。
注意到 ,因此, 当且仅当 。也就是说,我们通过求出 ,绕过了困难(
$$a_i=1+\max_{u\in S_i,d_u\ge d_i+p_i,c_u\ge c_i}h_u $$我不会)的求 ,转而解决简单的判定 是否等于 的问题。枚举子序列的第二个点,有因此只需判断是否有
即可求出 。变形一下,上式即为判断是否有
开 棵动态开点线段树,将所有点按照 从大到小排序,插入点 时令第 棵线段树 处的值对 取 ,查询 时判断其子树 区间内最大值是否不小于 即可。这一部分的总时间复杂度为 。
总时空复杂度均为 。这题字符集很小,代码里没有实现离散化:
#include<bits/stdc++.h> namespace IO{ const int L=(1<<20)+30; char buf[L],*s,*t,pbuf[L],*p=pbuf; #define gf() (s==t&&(s=buf)==(t=buf+fread(buf,1,L,stdin))?-1:*s++) void rd(int&x){ x=0;char c=gf(); while(c<48) c=gf(); while(c>=48) x=x*10+(c^48),c=gf(); } void rd(char*x){ do *x=gf();while(*x<48); while(*x>=48) *x-='a'-1,*++x=gf(); *x=0; } void fl(){fwrite(pbuf,1,p-pbuf,stdout),p=pbuf;} void pf(char c){if(p-pbuf==L) fl();*p++=c;} void wt(int x){ static int st[30],tp; do st[++tp]=x%10,x/=10;while(x); while(tp) pf(st[tp--]|48); pf(10); } } using IO::rd; using IO::wt; using namespace std; const int N=100005; int n,m=26,maxr,p[N],dep[N],ans[N],dfn[N],sz[N],tim,len[N],son[N],s[N],h[N],rt[N],idx; struct tn{int Ls,Rs,v;}tr[N*18]; #define ls tr[u].Ls #define rs tr[u].Rs vector<int>E[N],F[N]; char c[N]; int query(int u,int L,int R,int l=1,int r=maxr){ if(!u||(L<=l&&r<=R)) return tr[u].v; int mid=(l+r)/2,z=0; if(L<=mid) z=query(ls,L,R,l,mid); if(R>mid) z=max(z,query(rs,L,R,mid+1,r)); return z; } void insert(int&u,int x,int v,int l=1,int r=maxr){ if(!u) tr[u=++idx]={0,0,0}; if(tr[u].v=max(tr[u].v,v),l<r){ int mid=(l+r)/2; x>mid?insert(rs,x,v,mid+1,r):insert(ls,x,v,l,mid); } } int merge(int u,int v){ if(!u||!v) return u^v; ls=merge(ls,tr[v].Ls),rs=merge(rs,tr[v].Rs); return tr[u].v=max(tr[u].v,tr[v].v),u; } void getdep(int x,int pr){ sz[x]=1; for(int y:E[x]) if(y^pr){ dep[y]=dep[x]+1,getdep(y,x),sz[x]+=sz[y]; if(len[y]>len[son[x]]) son[x]=y; } len[x]=son[x]?len[son[x]]:dep[x]; } void dfs(int x,int pr){ dfn[x]=++tim; if(son[x]) dfs(son[x],x),rt[x]=rt[son[x]]; for(int y:E[x]) if(y^pr&&y^son[x]){ dfs(y,x),rt[x]=merge(rt[x],rt[y]); for(int i=dep[y];i<=len[y];++i) s[dfn[x]+i-dep[y]+1]=max(s[dfn[x]+i-dep[y]+1],s[dfn[y]+i-dep[y]]); } h[x]=1+query(rt[x],c[x],m); insert(rt[x],c[x],h[x]),s[dfn[x]]=tr[rt[x]].v; ans[x]=len[x]<dep[x]+p[x]?1:s[dfn[x]+p[x]]; F[int(c[x])].emplace_back(x); } #define eb emplace_back int main(){ rd(n); for(int i=1;i<=n;++i) rd(p[i]); rd(c+1); for(int i=1,u,v;i<n;++i) rd(u),rd(v),E[u].eb(v),E[v].eb(u); getdep(1,1),maxr=m,dfs(1,1),idx=0,maxr=n; for(int i=1;i<=n;++i) rt[i]=0; for(int i=m;i;--i){ for(int x:F[i]) insert(rt[h[x]],dfn[x],dep[x]); for(int x:F[i]) if(sz[x]>1) ans[x]+=query(rt[ans[x]],dfn[x]+1,dfn[x]+sz[x]-1)>=dep[x]+p[x]; } for(int i=1;i<=n;++i) wt(ans[i]); return IO::fl(),0; }
- 1
信息
- ID
- 9876
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者