CSP模拟58联测20 T3 注视一切的终结
CSP模拟58联测20 T3 注视一切的终结
Ps:链接为衡水中学OJ。
去除重边以后是树,而我们需要使一个点到另外一个点的简单路径上相邻边的颜色尽可能不相同。
发现如果一条边有
然后把边权下压至儿子的点权。
可以
设
初始时
转移时枚举
其中
对于查询,先求出
如果
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
struct node
{
int to,nxt,w;
}edge[maxn*4];
int n,m,tot;
int head[maxn],dp[maxn][22][4][4],f[maxn][21],deep[maxn],col[maxn][5],cx[5],cy[5],cnt[maxn];
bool vis[maxn];
void add(int x,int y,int z)
{
tot++;
edge[tot].to=y;
edge[tot].nxt=head[x];
edge[tot].w=z;
head[x]=tot;
}
void dfs1(int u,int fa)
{
vis[u]=true;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa)
{
if(cnt[u]==3) continue;
bool flg=1;
for(int j=0;j<cnt[u];j++) if(col[u][j]==edge[i].w){flg=0;break;}
if(flg) col[u][cnt[u]++]=edge[i].w;
}
else if(!vis[v]) dfs1(v,u);
}
}
void dfs2(int u,int fa)
{
vis[u]=true;
deep[u]=deep[fa]+1;
f[u][0]=fa;
if(u!=1)
{
for(int a=0;a<cnt[u];a++)//初始化
for(int b=0;b<cnt[fa];b++)
dp[u][0][a][b]=(col[u][a]!=col[fa][b]);
}
for(int i=1;(1<<i)<=deep[u];i++)//dp 转移
{
f[u][i]=f[f[u][i-1]][i-1];
int y=f[u][i-1],z=f[u][i];
for(int a=0;a<cnt[u];a++)//a,b,c 均枚举颜色
for(int b=0;b<cnt[y];b++)
for(int c=0;c<cnt[z];c++) dp[u][i][a][c]=max(dp[u][i][a][c],dp[u][i-1][a][b]+dp[y][i-1][b][c]);
}
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(vis[v]) continue;
dfs2(v,u);
}
}
int Lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
for(int i=20;i>=0;i--) if(deep[f[x][i]]>=deep[y]) x=f[x][i];
if(x==y) return x;
for(int i=20;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int jump(int x,int dis,int c[])//点 x 向上跳 dis 步的最大答案
{
int now=x;
for(int i=0;i<=20;i++)
{
if(((dis>>i)&1)==0) continue;
int cc[5];
memset(cc,0,sizeof(cc));
for(int a=0;a<cnt[now];a++)
for(int b=0;b<cnt[f[now][i]];b++) cc[b]=max(cc[b],c[a]+dp[now][i][a][b]);
memcpy(c,cc,sizeof(cc));
now=f[now][i];
}
return now;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dfs1(1,0);
memset(vis,0,sizeof(vis));
dfs2(1,0);
int q;
scanf("%d",&q);
for(int qq=1;qq<=q;qq++)
{
int x,y;
memset(cx,0,sizeof(cx)),memset(cy,0,sizeof(cy));
scanf("%d%d",&x,&y);
int lca=Lca(x,y),fx,fy,ans=0;
if(x!=lca) fx=jump(x,deep[x]-deep[lca]-1,cx);
if(y!=lca) fy=jump(y,deep[y]-deep[lca]-1,cy);
if(x==lca) for(int i=0;i<cnt[fy];i++) ans=max(ans,cy[i]);
else if(y==lca) for(int i=0;i<cnt[fx];i++) ans=max(ans,cx[i]);
else
for(int a=0;a<cnt[fx];a++)
for(int b=0;b<cnt[fy];b++) ans=max(ans,cx[a]+cy[b]+(col[fx][a]!=col[fy][b]));//最后枚举颜色
printf("%d\n",ans);
}
}
分类:
多校联测
, 动态规划/dp / 区间 dp
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现