P5180-[模板]支配树

1|0正题

题目链接:https://www.luogu.com.cn/problem/P5180


1|1题目大意

给出n个点的一张有向图,求每个点支配的点数量。

1n2×105,1m3×105


1|2解题思路

首先定义半支配点semix表示对于点x寻找一个dfn序最小的点y满足存在一条yx的路径去掉头尾之后所有点的dfn序都大于x的。

考虑怎么求每个点的半支配点,考虑两种情况对于一个能够直接到达x的点y

  1. dfny<dfnx:那么y可能是x的半支配点
  2. dfny>dfnx:那么设v表示ydfs根节点的路径上的某个点udfn序最小的半支配点,那么v可能是u的半支配点

主要是第二种情况我们相当于要找一个在某个点到根节点路径上的点使得它的半支配点dfn序最小。

那么可以考虑倒序枚举,然后用带权并查集维护那个半支配点编号最小的。

之后就是半支配点有什么用,大概就是半支配点向点连边那么新的图支配关系不变。

所以一种暴力的做法就是直接跑DAG的支配树求法,但是有更快的。

考虑对于一个点x和它的半支配点y,如果yx的路径上我们找到一个半支配点dfn序最小的节点u且它的半支配点v
那么如果

  1. v=y,那么证明整条路径上没有dfn序更小的半支配点,y就是x的支配点。
  2. du>dy,那么显然u有更小的支配点支配这套路径,所以u的支配点就是y的支配点

这个过程中uv的维护和上面一样,所以可以一起求解。

但是我们可以暂时不知道u的支配点,所以可以先记录,最后在正序的记回去。

时间复杂度O(nα(n))


1|3code

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2100; struct node{ int l,r; }q[110000]; int n,m,k,t,ans,p[N],st[N][26],ss[N][26],nxt[N],f[N][N],pre[N][N]; char T[N],S[N]; bool cmp(node x,node y) {return x.l<y.l;} int main() { freopen("lcs.in","r",stdin); freopen("lcs.out","w",stdout); scanf("%s",T+1);m=strlen(T+1); scanf("%s",S+1);n=strlen(S+1); for(int i=1;i<=m;i++){ for(int j=0;j<26;j++) st[i][j]=st[i-1][j]+(T[i]=='a'+j); } for(int i=1;i<=n;i++){ for(int j=0;j<26;j++) ss[i][j]=ss[i-1][j]+(S[i]=='a'+j); } scanf("%d",&k); for(int i=1;i<=k;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].l++,q[i].r++; sort(q+1,q+1+k,cmp); int nowr=0,pr=0; for(int i=1;i<=k;i++){ if(q[i].l>nowr){ nxt[pr]=nowr; for(int j=nowr+1;j<q[i].l;j++)nxt[j]=j; pr=q[i].l;nowr=q[i].r; } else nowr=max(q[i].r,nowr); } nxt[pr]=nowr; for(int i=nowr+1;i<=n;i++)nxt[i]=i; for(int i=1;i<=n;i++) if(nxt[i])p[++t]=i; for(int i=1;i<=m;i++) for(int j=1;j<=t;j++){ int l=p[j],r=nxt[l],L=i; for(int z=min(r-l,m-L);z>=0;z--){ bool flag=1; for(int k=0;k<26;k++) if(ss[r][k]-ss[l-1][k]<st[L+z][k]-st[L-1][k]) {flag=0;break;} if(flag){pre[i][j]=z+1;break;} } } for(int i=1;i<=m;i++) for(int j=1;j<=t;j++){ int l=p[j],r=nxt[l],R=i; if(pre[i][j]==r-l+1)continue; for(int z=min(r-l,R-1)-1;z>=0;z--){ bool flag=1; for(int k=0;k<26;k++) if(ss[r][k]-ss[l-1][k]<st[R][k]-st[R-z-1][k]) {flag=0;break;} if(flag){f[i+1][j+1]=z+1;ans=max(ans,z+1);break;} } } for(int i=1;i<=m;i++) for(int j=1;j<=t;j++){ int l=p[j],r=nxt[l]; if(pre[i][j]==r-l+1){ f[i+r-l+1][j+1]=max(f[i+r-l][j+1],f[i][j]+r-l+1); ans=max(ans,f[i][j]+r-l+1); } ans=max(ans,f[i][j]+pre[i][j]); } printf("%d\n",ans); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15001862.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(44)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示