CSP模拟58联测20 T3 注视一切的终结

题面及数据范围

Ps:链接为衡水中学OJ。

去除重边以后是树,而我们需要使一个点到另外一个点的简单路径上相邻边的颜色尽可能不相同。

发现如果一条边有 \(3\) 种或以上的颜色,那么该边肯定可以与相邻边不同,所以把 \(\geq3\) 的情况均看为 \(3\) 的情况。

然后把边权下压至儿子的点权。

可以 \(log_2n\) 的倍增求出 \(lca\) 同时也可以通过倍增求最大贡献。

设 \(f[u][i][a][b]\) 表示从 \(u\) 向上跳 \(2^i\) 步,开始颜色为 \(a\),结束颜色为 \(b\) 的最大贡献,其中 \(a \leq 3,b \leq 3\)。(实际上已经跳到了 \(2^i+1\) 这个点,但因为点权是连向父亲的边权,所以我们不需要 \(2^i+1\) 这个点的点权)

初始时 \(f[u][0][a][b]=col[a]\neq col[b]\)。

转移时枚举 \(x,y=fa[x][i-1],z=fa[x][i]\) ,设颜色为 \(a,b,c\) 则 \(f[x][i][a][c]=\max(f[x][i-1][a][b]+f[y][i-1][b][c])\)。

其中 \(z\) 是用来枚举终点的颜色。

对于查询,先求出 \(lca\)。

如果 \(lca=x\) 或 \(lca=y\) 那么直接求出另一点的 \(lca\) 的最大值;否则在枚举最后两条边的颜色。

#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);
}
}

CSP模拟58联测20 T3 注视一切的终结的更多相关文章

  1. @CSP模拟2019.10.16 - T3@ 垃圾分类

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 为了保护环境,p6pou建设了一个垃圾分类器. 垃圾分类器是一个 ...

  2. NOIP模拟 17.8.20

    NOIP模拟17.8.20 A.阶乘[题目描述]亲爱的xyx同学正在研究数学与阶乘的关系,但是他喜欢颓废,于是他就制作了一个和阶乘有关系的数学游戏:给出两个整数 n,m,令 t = !n,每轮游戏的流 ...

  3. csp模拟赛低级错误及反思

    \(csp\)模拟赛低级错误及反思. 1.没开\(longlong\). 反思:注意数据类型以及数据范围. 2.数组越界(前向星数组未开两倍,一题的数据范围应用到另一题上,要开两倍的写法为开两倍数组) ...

  4. CSP模拟赛2游记

    这次由于有课迟到30min,了所以只考了70min. 调linux配置调了5min,只剩下65min了. T1:有点像标题统计,但要比他坑一点,而且我就被坑了,写了一个for(int i=1;i< ...

  5. CSP模拟赛游记

    时间:2019.10.5 考试时间:100分钟(连正式考试时间的一半还没有到)题目:由于某些原因不能公开. 由于第一次接触NOIinux系统所以连怎么建文件夹,调字体,如何编译都不知道,考试的前半小时 ...

  6. Noip模拟58 2021.9.21(中秋祭&&换机房祭)

    第一次在学校过中秋节,给家里人视频电话,感觉快回家了很开心, 然后还吃了汉堡喝饮料非常爽,颓废了一会儿还换了新机房,$Linux2.0$非常dei,少爷机也非常快, 发现好像测评机又成了老爷机,这就是 ...

  7. @省选模拟赛03/16 - T3@ 超级树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...

  8. 2021.9.21考试总结[NOIP模拟58]

    T1 lesson5! 开始以为是个无向图,直接不懂,跳去T2了. 之后有看了一眼发现可暴力,于是有了\(80pts\). 发现这个图是有拓扑序的,于是可以用拓扑排序找最长路径.先找原图内在最长路径上 ...

  9. csp-s模拟测试101的T3代码+注释

    因为题目过于大神所以单独拿出来说.而且既然下发std了颓代码貌似也不算可耻233 很难讲啊,所以还是写在代码注释里面吧 因为比较认真的写了不少注释,所以建议缩放到80%观看,或者拿到gedit上 1 ...

  10. csp模拟69

    考试一眼看出$T3$原题,但是没做过,心态爆炸. 然后去看$T1$,迷之认为它是矩阵快速幂?推了一个小时,发现在转移过程中方案数并不均匀分布,然后就挂了. 决定先去看T3,只会$O(n\sqrt{n} ...

随机推荐

  1. java游戏服务器2023年7月22日

    name 卡牌军团 放置卡牌游戏 开发语言: java mysql 通信http 账号服务器 提供验证等功能 中心服务器 跨服功能 排行榜 公会

  2. C# WinForm 解除资源文件的占用并删除

    1.删除未解除占用的资源时 2.调用Windows API函数 解除文件占用 [DllImport("kernel32.dll", SetLastError = true)] [r ...

  3. C#|.net core 基础 - 如何判断连续子序列

    前两天同事遇到了一个小需求,想判断一个集合是不是在另一个集合中存在,并且要求顺序一致,然后一起讨论了下应该怎么做,有没有什么比较好的方式?下面分享一下我们想到的方法,如果你也有不同的想法也可以分享给我 ...

  4. JavaScript – Set and Map

    参考 Set 和 Map 数据结构 Set 介绍和使用 Set 很像 Array, 但其实它是一个 Iteralbe 对象. 用于保存多个值, 而且具有 unique 特性 (1 个 set 里面不会 ...

  5. linux 映射windows 下的共享文件夹

    linux 映射windows 下的共享文件夹     本文讯]2021年4月27日  在对接第三方系统,进行数据采集的时候,对方给了我们一个文件夹,里面全是txt文件,这个时候就要想办法获取他们数据 ...

  6. grid网格布局

    https://ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html Grid 布局只对项目生效 划分网格的线,称为"网格线" ...

  7. [TK] HH的项链 离线树状数组解法

    实际上这题很难和树状数组联系起来,我感觉效率也不是很高,感觉不是正解 怎么使用树状数组 这道题我们很容易想到一点:同种物品在一个区间内只能出现一次,先不考虑别的问题,我们想出下面这种使用树状数组的思路 ...

  8. mono 下运行 VB.NET 编写的 WinForm 程序

    操作系统环境 UOS  20 安装 Mono 可以参考 dotnet 在 UOS 国产系统上安装 Mono 开发工具的方法 要点如下 nano /etc/apt/sources.list 增加一行 D ...

  9. VB.NET 在 Windows下通过WIn32API获取CPU和内存的使用率

    .net 要获取CPU和内存的使用率,一般是通过 PerformanceCounter 或者 WMI 查询得到,但是如果操作系统经常不正常断电或者别的什么原因,让系统的性能计数器抽风了,可能就会造成初 ...

  10. PHP运算符优先级(摘自在线工具)

    PHP运算符优先级 结合方向 运算符 附加信息 非结合 clone new clone 和 new 左 [ array() 非结合 ++ -- 递增/递减运算符 非结合 ~ - (int) (floa ...