首页 > 其他分享 >ABC335E题解

ABC335E题解

时间:2024-01-10 10:11:43浏览次数:42  
标签:ch read 题解 点权 路径 ABC335E dp

洛谷题面
感觉有点毒瘤,不过还是有些 trick 在的。

题意翻译(复制于洛谷题面):

给定一个 \(N\) 个点 \(M\) 条无向边的图,图上每个点都有其颜色。求所有经过点权单调不降的路径中,出现的不同颜色的个数最多是多少。

由于是单调不降的路径,所以可以点权大的点到点权小的点的路径对结果没有影响,可以当有向边连。
点权相同且相连的点可以来回走,对结果没有影响,可以缩成一个点。

这样这张无向图就变成了由点权小的点到点权大的点的 DAG。

建图的时候把所有边先存起来,等用并查集将所有点缩成一个的时候再连边。

然后我们可以在这张图上来计 \(1\) 到 \(N\) 这条路径上不同颜色的个数。

有的题解里用了 Dijkstra 等算法,由于 DAG 的性质所以求解的本质一样,不再赘述。

由于是 DAG,所以可以跑拓扑排序,但是直接 dp 是不对的,有可能变为了以其他点为起点到 \(N\) 的路径。

我们可以将其他点的 dp 值初始化为负无穷,然后 \(1\) 点的 dp 值为 \(1\),此时进行转移要么是 \(1\) 到 \(N\) 路径的值,要么是负无穷,进行一次判断即可。

代码如下。

#include<bits/stdc++.h>
using namespace std;
template<typename T>
T read(){
    T f=1,x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return f*x;
}
constexpr int MAXN=2e5+10,MAXM=2e5+10;
int n,m,a[MAXN],fa[MAXN],cnt,head[MAXN],tcnt,dp[MAXN],in[MAXN];
bool vis[MAXN];
struct EDGE1{
    int v,nxt;
}edge[MAXM];
struct EDGE2{
    int u,v;
}tedge[MAXM];
void add(int u,int v){
    edge[++cnt]={v,head[u]};
    head[u]=cnt;
    ++in[v];
}
namespace sol{
    int sget(int x){
        if(fa[x]==x)return x;
        else return fa[x]=sget(fa[x]);
    }
    void merge(int x,int y){
        fa[sget(y)]=sget(x);
    }
    void solve(){
        n=read<int>();m=read<int>();
        for(int i=1;i<=n;++i){
            a[i]=read<int>();
            fa[i]=i;
        }
        for(int i=1,u,v;i<=m;++i){
            u=read<int>();v=read<int>();
            if(a[u]==a[v])merge(u,v);
            else{
                if(a[u]>a[v])swap(u,v);
                //a[u]<a[v] 
                tedge[++tcnt]={u,v};
            }
        }
        for(int i=1;i<=tcnt;++i){
            add(sget(tedge[i].u),sget(tedge[i].v));
        }
        queue<int>q;
        for(int i=1;i<=n;++i){
        	if(!in[sget(i)]){
        		in[sget(i)]=1;
        		q.push(sget(i));
			}
		}
		memset(dp,0x80,sizeof(dp));
		dp[sget(1)]=1;
        while(!q.empty()){
        	int u=q.front();q.pop(); 
            for(int i=head[u];i;i=edge[i].nxt){
            	int v=edge[i].v;
            	dp[v]=max(dp[u]+1,dp[v]);
            	--in[v];
            	if(in[v]==0){
            		q.push(v);
				}
			}
        }
        printf("%d\n",max(dp[sget(n)],0));
    }
}
int main(){
    sol::solve();
    return 0;
}

标签:ch,read,题解,点权,路径,ABC335E,dp
From: https://www.cnblogs.com/LiJoQiao/p/17955920

相关文章

  • 复旦大学2023--2024学年第一学期(23级)高等代数I期末考试第七大题解答
    七、(10分) 设$A$为$n\,(n>1)$阶非异阵,$B$是$A$的逆阵. 任取$r$个指标$1\leqi_1<i_2<\cdots<i_r\leqn$, 剩余的指标记为$1\leqi_{r+1}<\cdots<i_n\leqn$.证明:$$|A|\cdotB\begin{pmatrix} i_1&i_2&\cdots&i_r\\ i_1&i_2&......
  • IOS移动端,表单input聚焦时页面放大的问题解析以及解决办法
    在移动端开发H5项目中,发现页面在使用iPhone访问的时候,点击input和textarea等文本输入框聚焦focus()时,页面会整体放大,而且失去焦点之后页面不能返回原来的样子。原因:苹果系统觉得点击输入框放大是一个“很好”的体验,就擅自把页面给放大了,触发机制,IOS端input字体应大于15px,否......
  • Trie字符串统计题解
    维护一个字符串集合,支持两种操作:"Ix"向集合中插入一个字符串x;"Q×"询问一个字符串在集合中出现了多少次。共有N个操作,输入的字符串总长度不超过105,字符串仅包含小写英文字母。输入格式第一行包含整数N,表示操作数。接下来N行,每行包含一个操作指令,指令为"l×"或"Q×"中的一种。......
  • CF1536F Omkar and Akmar 题解
    思路首先最后的局面在两两字母间一定不会多于\(1\)个空格。考虑反证,假设有两个空格,那么有以下两种情况:\(\text{A}\_\_\text{B}\),\(\text{A}\_\_\text{A}\),也就是两边的字母不同,相同。对于第一种,在任意一个空格都可以填一个与他相邻字符不同的字符,对于第二种,填\(\text{B}\)......
  • CF1527D MEX Tree 题解
    思路如果一条路径的\(\text{mex}=k\),那么\(0\simk-1\)这些点一定在路径中出现过,并且一定在一条链上。如果不在一条链上,那么就不满足简单路径这一条件了。因此我们在从小到大加点的过程中如果发现一个点不在已求出的链上,那么比这个点编号大的\(k\)答案一定都是\(0\)了......
  • [ABC329E] Stamp 题解
    正难则反。直接往上覆盖不好做,那么可以考虑把字符从\(S\)上往下删。删的过程就是在\(S\)中找\(T\)并把他们变成#。如果\(S\)中有字符为#,那我们可以把它看成任意字符,因为向上贴的过程中有重复覆盖的情况,在删的时候我们并不知道他是否重复了,所以当成任意字符来看即可(这也......
  • [ABC331F] Palindrome Query 题解
    思路判断一个字符串是否是回文串,可以从它的本质出发:正着读和倒着读是一样的。快速判断它正着和反着是否一样,用字符串哈希即可。又因为涉及单点修改,区间查询,那么使用线段树维护这两个值就行了。这里讲一下如何pushup。以正着的哈希值为例:我们要更新\(p\)这个点的\(hash\)值,......
  • 1 月杂题题解
    好久没写博客了?今晚写爽。P5311成都七中这有黑?对于一个点\(x\),设其子树任意一点为\(y\)。我们可以求出这\(x\rightarrowy\)这条路径经过节点的的\(l,r\)。遍历\(x\)的子树,我们可以得到一些三元组\((l,r,c)\)表示\(x\)所属连通块包含了\(l,r\)这些节点,就有一......
  • [ABC273D] LRUD Instructions 题解
    [ABC273D]LRUDInstructions题解很好的一道大模拟,使我爆\(0\)。思路解析大模拟,我们只需要用一个\(x,y\)表示我们当前的位置,而对于每一个移动,我们就判断在当前移动方向上离当前点最近的点,若该点在当前行进路线上,则把当前位置设为该点前面的一个。其中判断在当前移动方向上......
  • CF1045G AI robots题解
    题目链接:洛谷或者CF本题考虑转化为cdq分治模型对于cdq分治来说,只需要考虑左边对右边的影响,那我们要考虑该怎样设置第一维度的左右对象。很显而易见的是抛开\(q\)限制而言,我们着眼于,如何让双方互相看到的严格条件转化为只需要关注单体看见。考虑什么情况下只需要一方看到......