题目链接:https://www.luogu.com.cn/problem/P5180
给出n个点的一张有向图,求每个点支配的点数量。
1≤n≤2×105,1≤m≤3×105
首先定义半支配点semix表示对于点x寻找一个dfn序最小的点y满足存在一条y到x的路径去掉头尾之后所有点的dfn序都大于x的。
考虑怎么求每个点的半支配点,考虑两种情况对于一个能够直接到达x的点y
- dfny<dfnx:那么y可能是x的半支配点
- dfny>dfnx:那么设v表示y到dfs根节点的路径上的某个点u的dfn序最小的半支配点,那么v可能是u的半支配点
主要是第二种情况我们相当于要找一个在某个点到根节点路径上的点使得它的半支配点dfn序最小。
那么可以考虑倒序枚举,然后用带权并查集维护那个半支配点编号最小的。
之后就是半支配点有什么用,大概就是半支配点向点连边那么新的图支配关系不变。
所以一种暴力的做法就是直接跑DAG的支配树求法,但是有更快的。
考虑对于一个点x和它的半支配点y,如果y到x的路径上我们找到一个半支配点dfn序最小的节点u且它的半支配点为v。
那么如果
- v=y,那么证明整条路径上没有dfn序更小的半支配点,y就是x的支配点。
- du>dy,那么显然u有更小的支配点支配这套路径,所以u的支配点就是y的支配点
这个过程中u和v的维护和上面一样,所以可以一起求解。
但是我们可以暂时不知道u的支配点,所以可以先记录,最后在正序的记回去。
时间复杂度O(nα(n))
#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__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .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语句:使用策略模式优化代码结构