>A->B->C-


 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述


 

一天小A在金色的银杏树下向他喜欢的小姐姐B表白了,“对不起,我喜欢的是C”,B这样说道,小A尴尬的笑了笑转身离开了。他心里默默说着“对不起,C喜欢我。”(233333333)

Love triangle被定义为:如果A喜欢B,B喜欢C,C喜欢A则称为Love triangle。现在让你寻找有没有Love triangle。

 

 

输入描述:


 

第一行一个正整数N(n<=5000),第二行n个数X1,X2,X3……Xn代表i喜欢Xi。

输出描述:

如果存在Love triangle则输出YES,没有则输出NO。

示例1

输入

复制

5
2 4 5 1 3

输出

复制

YES

长见识,真厉害,这个题刷新了我的定义啊,我一直以为判断有向环呢,结果是一个思维,我真是大吐血,看了答案都想跳楼的那种。直接三层嵌套,暴力求解法,真是帅气的不要不要的。

#include<stdio.h>

#include<string.h>

#include<algorithm>

using namespace std;

int n,a[5050];

int main()

{

    scanf("%d",&n);

    for(int i=1;i<=n;i++)

        scanf("%d",&a[i]);

    for(int i=1;i<=n;i++)

        if(a[a[a[i]]]==i)

            return puts("YES"),0;

    return puts("NO"),0;

}

<think>我们有一个需求:将branch2合并到branch1,使得提交历史变为线性顺序A->B->C->D。根据Git的合并机制,通常有两种合并方式:快速前进(fast-forward)和普通合并(生成一个新的合并提交)。但这里我们希望得到线性的提交历史,即没有分叉,也没有合并提交。分析:假设当前分支branch1的提交历史是A->B,而branch2的提交历史是A->B->C->D(即branch2是从branch1的B提交之后开始开发的)。如果branch1在B之后没有新的提交,那么将branch2合并到branch1时,Git默认会使用快速前进(fast-forward)模式,这样branch1就会直接指向D,历史就是A->B->C->D,线性。但是,如果branch1在B之后也有新的提交(比如提交E),那么合并branch2到branch1时,Git会执行一次三方合并(base是B,branch1的提交是E,branch2的提交是D),并生成一个新的合并提交(比如F),这样历史就会变成:A->B->E\\-> F/C->D这显然不是我们想要的线性历史。因此,为了实现线性历史,我们需要确保在合并时使用“变基(rebase)”而不是“合并(merge)”。具体步骤如下:步骤1:切换到branch2分支,然后将其变基到branch1上(这样branch2的提交就会在branch1的当前提交之后重新应用,形成线性历史)。步骤2:切换回branch1分支,然后合并branch2(此时使用快速前进模式,因为branch2的提交已经基于branch1的最新提交)。但注意:我们的目标是将branch2合并到branch1,并且最终branch1的提交历史为A->B->C->D。假设当前我们在branch1分支上,并且branch1的提交历史是A->B(可能还有新的提交,比如E),而branch2的提交历史是B->C->D(从B开始)。为了得到线性历史,我们可以这样做:方法1(使用变基):1.将branch2变基到branch1上(这样branch2的提交就会接在branch1的最新提交之后,变成E->C'->D',注意提交哈希会变)。2.然后将branch1快速前进到branch2的最新提交(即D')。方法2(另一种方式,更直接):1.切换到branch1分支:`git checkoutbranch1`2.将branch2分支变基到branch1上:`gitrebasebranch1branch2`#这样branch2的提交就会基于branch1的当前提交重新应用3.然后切换回branch1:`gitcheckout branch1`4.合并branch2(此时branch2的提交在branch1之后,所以可以快速前进):`git mergebranch2`但是,如果branch1在B之后有新的提交(比如E),那么变基后的branch2将变成E->C'->D',然后合并到branch1后,branch1的历史就是A->B->E->C'->D'。然而,我们想要的是A->B->C->D,而不是包含E。所以这里需要明确:如果branch1在B之后有新的提交,那么这些提交(E)将会在变基过程中被branch2的提交(C和D)重新应用在其上,从而改变提交顺序。但注意,我们可能并不想保留E?或者我们想要的是将branch2的提交直接接到B后面?实际上,需求是最终提交历史为A->B->C->D。这意味着我们可能希望忽略branch1在B之后的所有提交(如果有的话),或者我们假设branch1在B之后没有提交。如果branch1在B之后有提交,那么我们就不能简单地通过合并来得到A->B->C->D,因为branch1的提交也是历史的一部分。因此,我们需要明确:如果branch1在B之后没有新的提交,那么直接使用快速前进合并即可。如果有新的提交,而我们又希望丢弃这些提交,只保留branch2的提交,那么我们可以使用重置(reset)而不是合并。但是,问题描述中并没有提到branch1在B之后是否有提交。我们只能按照两种情况讨论:情况1:branch1在B之后没有新的提交(即branch1指向B,branch2指向D,且D是B的后继提交)。此时,我们可以直接合并(使用快速前进):git checkoutbranch1git mergebranch2#快速前进,branch1指向D情况2:branch1在B之后有新的提交(比如E),但我们希望最终的历史是A->B->C->D(即丢弃E,或者将E放在D之后?需求是A->B->C->D,所以E应该被丢弃?)。如果需求是丢弃branch1在B之后的所有提交(即E),而只保留branch2的提交(C和D),那么我们可以这样做:git checkoutbranch1git reset--hardbranch2#将branch1分支强制指向branch2的提交(D),丢弃branch1在B之后的所有提交(E)注意:这样会丢弃提交E,所以请确保E不再需要。但是,如果需求是保留E,但希望历史是线性的A->B->C->D->E,那么我们需要将branch1的提交(E)变基到branch2上,然后再合并。不过,需求是A->B->C->D,所以E不应该出现。因此,根据需求,我们想要的是branch2的提交历史(A->B->C->D),而branch1应该指向D。所以,如果branch1在B之后没有提交,就合并(快速前进);如果有提交但不需要,就重置。然而,问题描述中并没有说明branch1在B之后是否有提交,以及这些提交是否需要。所以我们需要更通用的方法:将branch1重置到branch2。步骤:1.切换到branch1分支:`gitcheckout branch1`2.将branch1分支重置到branch2的提交:`gitreset --hard branch2`3.这样,branch1就指向了branch2的提交(D),历史就是A->B->C->D。注意:这个方法会丢弃branch1在B之后的所有提交(如果有的话)。如果这些提交需要保留,那么就不能这样做。另一种情况:如果我们希望保留branch1在B之后的所有提交,但希望它们出现在branch2的提交之后(即A->B->C->D->E),那么我们可以:gitcheckout branch1gitrebasebranch2#将branch1的提交(E)变基到branch2上(即D之后),这样历史就是A->B->C->D->E#然后,我们还需要将branch1合并到branch2?不对,我们的目标是将branch2合并到branch1,现在branch1已经在E了,而branch2还在D。所以我们需要让branch1包含branch2的提交,同时保留自己的提交。但是,需求是最终提交历史为A->B->C->D,所以我们不需要E。因此,结论是:根据需求,我们想要branch1指向D,而不管branch1之前是否有新的提交。所以使用`gitreset --hard`是最直接的方法。然而,我们还需要考虑远程分支的情况和协作问题,因为重置会改变历史,如果branch1已经被推送到远程,那么强制推送可能会影响其他人。所以,如果branch1是公共分支(已经被其他人拉取),那么重置并强制推送是不推荐的。在这种情况下,我们可以使用合并,但合并会产生分叉,不符合线性要求。因此,我们需要根据实际情况选择:-如果branch1是本地分支,或者可以强制推送,那么使用重置。-否则,我们可能需要使用变基来重新整理提交,但这可能会改变提交的哈希值,同样需要强制推送。由于问题中没有说明分支是否公共,我们提供两种方案:方案一(适用于本地分支或允许强制推送):git checkoutbranch1git reset--hardbranch2#将branch1指向branch2的提交方案二(使用变基,适用于需要保留branch1在B之后的提交,但希望它们出现在branch2的提交之后的情况):#假设我们想要A->B->C->D->Egit checkoutbranch2#先切换到branch2gitrebasebranch1#将branch2的提交(C和D)变基到branch1(即E)之后?不对,branch1是包含E的,而branch2是从B开始的,所以变基branch2到branch1上,会变成E->C'->D'#然后,我们切换回branch1,再合并(快速前进):gitcheckout branch1gitmerge branch2#快速前进到D'这样历史就是:A->B->E->C'->D'但需求是A->B->C->D,所以这个方案不符合。因此,如果需求是严格的A->B->C->D,那么只能使用方案一(重置),前提是branch1在B之后的提交可以丢弃。总结:根据需求,我们想要branch1的提交历史变成branch2的提交历史(A->B->C->D),所以最简单的方法是将branch1重置到branch2的提交。操作命令:git checkoutbranch1git reset--hardbranch2注意:执行重置前,请确保branch1分支上的工作已经保存或不再需要,因为重置会丢弃branch1上未提交的更改以及branch1在B之后的提交。如果branch1在B之后有提交,并且这些提交需要保留,那么我们就不能丢弃。这时,我们需要重新考虑需求:最终提交历史为A->B->C->D,这意味着branch1在B之后的提交必须被丢弃?如果是,那么重置是可行的。如果branch1在B之后的提交需要保留,并且希望它们出现在branch2的提交之后,那么需求实际上变成了A->B->C->D->E,这可以通过将branch1变基到branch2上来实现:gitcheckout branch1gitrebasebranch2#将branch1的提交(E)重新应用到branch2(D)之后,变成D->E然后,历史就是A->B->C->D->E。但这样,branch2还没有包含E,所以合并branch2到branch1?不对,我们的目标是将branch2合并到branch1,现在branch1已经在E了,而branch2还在D。所以我们需要将branch1合并到branch2?不对,目标是将branch2合并到branch1,所以此时branch1已经包含了branch2(因为变基是基于branch2的),所以branch1现在就是D->E,而branch2还在D。那么我们可以将branch2指向branch1吗?这需要重置branch2。步骤:git checkoutbranch2git reset--hardbranch1#这样branch2也指向了E这样两个分支都指向了E,历史是A->B->C->D->E。但这样branch2的提交历史也被改变了,而且需求是合并branch2到branch1,最终branch1指向E,branch2指向E。但是,需求中并没有要求branch2的提交历史,所以可能也可以接受。不过,需求只要求branch1的提交历史为A->B->C->D,这里变成了A->B->C->D->E,不符合。所以,我们回到需求:最终提交历史为A->B->C->D。这意味着我们不需要E。因此,只能丢弃E。因此,我们采用方案一:重置。操作步骤:1.确保当前在branch1分支:`gitcheckout branch1`2.将branch1重置到branch2:`gitreset --hard branch2`这样,branch1就指向了branch2的提交,历史就是branch2的历史(A->B->C->D)。注意:如果branch1有未提交的更改,重置会覆盖它们,所以在重置前先提交或保存更改。另外,如果branch2是远程分支,需要先拉取确保本地branch2是最新的。如果branch1是公共分支,重置后需要强制推送到远程:`git push-f`。但请谨慎使用强制推送。因此,根据需求,我们使用重置命令。但是,问题描述中并没有提到丢弃branch1的提交,所以我们需要确认这样操作是否符合实际意图。如果用户不希望丢弃branch1的提交,那么可能需要重新考虑需求。综上所述,我们给出两种方法:方法A(丢弃branch1在B之后的提交,得到线性历史A->B->C->D):git checkoutbranch1git reset--hardbranch2方法B(保留branch1在B之后的提交,但历史会变成分叉后的合并,不符合线性要求):gitcheckout branch1gitmerge branch2#这会生成一个合并提交,历史不是线性的由于需求是线性历史A->B->C->D,所以我们选择方法A。因此,最终操作:git checkoutbranch1git reset--hardbranch2这样,branch1就指向了branch2的提交,历史就是A->B->C->D。注意:重置后,branch1本地分支和远程分支(如果有)会不同步,如果已经推送过,需要使用`gitpush -f`来强制推送更新远程分支。请确保在强制推送前通知团队成员,以免影响他人工作。如果branch2是远程分支,需要先拉取:gitfetch origingitcheckout branch1gitreset --hard origin/branch2#或者如果本地有branch2分支,确保它是最新的最后,请根据实际情况调整。</think>### 在 Git 中实现线性提交历史 A->B->C->D 的步骤 要合并分支 `branch2` 到 `branch1` 并实现**严格的线性提交历史 A->B->C->D**,需确保 `branch2` 的提交直接附加在 `branch1` 的最新提交之后,且不生成合并提交。以下是两种推荐方法: --- #### 方法 1:使用变基(Rebase)合并(推荐) 适用于 `branch1` 无新提交或需保留 `branch1` 提交的场景: ```bash # 1. 切换到 branch2 git checkout branch2 # 2. 将 branch2 的提交变基到 branch1 上(重放 C、D 到 branch1) git rebase branch1 # 3. 切换到 branch1 git checkout branch1 # 4. 快速前进合并(此时 branch1 指向 B,branch2 指向 D) git merge branch2 # 触发 Fast-Forward 合并 ``` **结果**: 提交历史变为线性:`A → B → C → D`,无合并提交。 --- #### 方法 2:强制重置(Hard Reset) 适用于**丢弃 `branch1` 在 B 之后的新提交**(如临时提交或无价值提交): ```bash # 1. 切换到 branch1 git checkout branch1 # 2. 强制将 branch1 指向 branch2 的提交(D) git reset --hard branch2 ``` **结果**: `branch1` 直接指向提交 D,历史为 `A → B → C → D`。 > **注意**: > - 重置会**永久丢弃 `branch1` 在 B 之后的新提交**,需谨慎使用[^1][^2]。 > - 若分支已推送远程,需强制推送:`git push -f origin branch1`(可能影响协作)。 --- ### 关键逻辑说明 1. **线性历史的本质**: Git 默认合并(`git merge`)会生成合并提交(如 `A→B→C→D→MergeCommit`),需通过**变基或重置**避免分叉[^3]。 2. **变基的作用**: `git rebase` 将 `branch2` 的提交(C、D)**复制到 `branch1` 最新提交之后**,形成连续历史链,使后续合并可快速前进(Fast-Forward)[^2][^3]。 3. **重置的风险**: `git reset --hard` 直接移动分支指针,**覆盖历史**,仅适用于无需保留 `branch1` 新提交的场景[^1][^4]。 --- ### 操作前后提交历史对比 | 操作前 | 操作后(目标) | |-----------------|-------------------| | `branch1`: A→B | `branch1`: A→B→C→D | | `branch2`: A→B→C→D | `branch2`: A→B→C→D | > **提示**:执行前建议备份分支(`git branch backup_branch1 branch1`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值