【学习笔记】CF627F Island Puzzle

这篇具有很好参考价值的文章主要介绍了【学习笔记】CF627F Island Puzzle。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

好啊,树上贪心题。

首先可以用类似于拓扑排序的过程将无用的节点全部删掉。

具体的,如果两个叶子节点对应的值恰好相同,那么同时将叶子节点删去;如果其中一个叶子节点对应的是 0 0 0,并且与父节点交换后相同,因为操作是可逆的,那么花费 1 1 1的代价将 0 0 0往中间挪,同时删去叶子节点;如果两个叶子节点对应的都是 0 0 0,那么有挪和不挪两种情况,如果不挪可以把整颗树删完那么就结束了,否则可以认为此时两个 0 0 0同时往中间挪。

观察到此时连一条边只能改变一个环上的点,因此如果有解那么一定只有两个叶子节点,也就是形成了一条路径。那么我们将路径连起来就形成了一个环。观察到 0 0 0只会往一个方向移动,一个数向左/右挪动的距离就是被交换的次数,因此贪心即可。

然后就做完了。

复杂度 O ( n ) O(n) O(n)文章来源地址https://www.toymoban.com/news/detail-431042.html

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define inf 0x3f3f3f3f3f3f3f3f
#define db double
#define cpx complex<db>
using namespace std;
const int N=2e5+5;
int n,a[N],b[N],totleaf,home[N],deg[N];
int aa[N],bb[N],cnt,rk[N];
ll res;
vector<int>G[N];
queue<int>Q;
vector<int>vec;
void dfs(int u){
    home[u]=1;
    aa[cnt]=a[u],bb[cnt]=b[u],cnt++;
    for(auto v:G[u]){
        if(!home[v])dfs(v);
    }
}
ll solve(){
    memset(rk,-1,sizeof rk);
    int p=0;while(p<cnt&&bb[p])p++;
    for(int i=0;i<cnt;i++)rk[aa[i]]=i;
    ll Min=inf,Max=-inf;
    for(int i=0;i<cnt;i++){
        if(bb[i]){
            ll D=(i-rk[bb[i]]+cnt)%cnt;
            Min=min(Min,D),Max=max(Max,D); 
        }
    }
    if(Max-Min>1){
        return inf;
    }
    if(Max==Min){
        return Max*(cnt-1);
    }
    else{
        int cnt1=0,cnt2=0;
        for(int i=(p+1)%cnt;i!=p;i=(i+1)%cnt){
            ll D=(i-rk[bb[i]]+cnt)%cnt;
            if(D==Max)cnt1++;
        }
        for(int i=(p+1)%cnt;i!=p;i=(i+1)%cnt){
            ll D=(i-rk[bb[i]]+cnt)%cnt;
            if(D==Max)cnt2++;
            else break;
        }
        if(cnt1!=cnt2)return inf;
        return Min*(cnt-1)+cnt1;
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)cin>>b[i];
    for(int i=1;i<n;i++){
        int u,v;cin>>u>>v;
        G[u].pb(v),G[v].pb(u);
        deg[u]++,deg[v]++;
    }
    for(int i=1;i<=n;i++){
        if(deg[i]==1){
            totleaf++;
            Q.push(i);
        }
    }
    while(Q.size()){
        int x=Q.front();Q.pop();
        if(!a[x]&&!b[x])continue;
        if(a[x]==b[x]){
            home[x]=1,totleaf--;
            for(auto y:G[x]){
                if(!home[y]&&--deg[y]==1){
                    Q.push(y),totleaf++;
                }
            }
        }
        else if(a[x]==0){
            int fa=0;
            for(auto y:G[x]){
                if(!home[y]){
                    fa=y;
                }
            }
            if(a[fa]==b[x]){
                swap(a[x],a[fa]),res++,home[x]=1,totleaf--;
                if(--deg[fa]==1){
                    Q.push(fa),totleaf++;
                }
            }
        }
        else if(b[x]==0){
            int fa=0;
            for(auto y:G[x]){
                if(!home[y]){
                    fa=y;
                }
            }
            if(b[fa]==a[x]){
                swap(b[x],b[fa]),res++,home[x]=1,totleaf--;
                if(--deg[fa]==1){
                    Q.push(fa),totleaf++;
                }
            }
        }
    }
    if(totleaf==1){
        cout<<0<<" "<<res<<"\n";
    }
    else{
        for(int i=1;i<=n;i++){
            if(a[i]==0&&b[i]==0&&deg[i]==1)Q.push(i);
        }
        while(Q.size()){
            int x=Q.front();Q.pop();
            int fa=0;
            for(auto y:G[x]){
                if(!home[y]){
                    fa=y;
                }
            }
            if(a[fa]==b[fa]){
                swap(a[x],a[fa]),swap(b[x],b[fa]),home[x]=1,res+=2,totleaf--;
                if(--deg[fa]==1)Q.push(fa),totleaf++;
            }
        }
        if(totleaf>2){
            cout<<-1<<"\n";
        }
        else{
            for(int i=1;i<=n;i++){
                if(deg[i]==1&&!home[i]){
                    vec.pb(i);
                }
            }
            dfs(vec[0]);
            ll res1=solve();
            reverse(aa,aa+cnt),reverse(bb,bb+cnt);
            res1=min(res1,solve());
            if(res1==inf){
                cout<<-1<<"\n";
            }
            else{
                cout<<vec[0]<<" "<<vec[1]<<" "<<res+res1<<"\n";
            }
        }
    }
}

到了这里,关于【学习笔记】CF627F Island Puzzle的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【学习笔记】CF607E Cross Sum

    分为两个部分求解。 首先考虑找到距离 ≤ r le r ≤ r 的交点数量。发现这等价于圆上两段圆弧相交,因此将圆上的点离散化后排序,用一个主席树来求就做完了。 然后是距离求和。这看起来非常棘手。事实上,只要把所有交点都找出来就做完了。首先可以放心的将圆环从一

    2024年02月02日
    浏览(32)
  • 【学习笔记】CF573E Bear and Bowling

    感觉贪心的做法比较自然🤔,推荐 这篇博客 非常经典 牛逼 的贪心思路: 考虑每次加入一个数,位置 i i i 的贡献为 V i = k i × a i + b i V_i=k_itimes a_i+b_i V i ​ = k i ​ × a i ​ + b i ​ ,其中 k i k_i k i ​ 表示 i i i 以前被选的位置的个数, b i b_i b i ​ 表示 i i i 以后被选的数的

    2024年02月07日
    浏览(34)
  • 【学习笔记】CF1783G Weighed Tree Radius

    如果 w v ( u ) w_v(u) w v ​ ( u ) 指代的就是直径,或者说我们再添一项 a v a_v a v ​ ,那么我们几乎就做完了。 于是自然而然想到换一个定义: d ( u , v ) = dist ( u , v ) + a u + a v d(u,v)=text{dist}(u,v)+a_u+a_v d ( u , v ) = dist ( u , v ) + a u ​ + a v ​ 。 发现这样转化过后,设直径的两个端点

    2024年02月16日
    浏览(36)
  • CF1881F Minimum Maximum Distance 题解 贪心+DFS

    You have a tree with n n n vertices, some of which are marked. A tree is a connected undirected graph without cycles. Let f i f_i f i ​ denote the maximum distance from vertex i i i to any of the marked vertices. Your task is to find the minimum value of f i f_i f i ​ among all vertices. For example, in the tree shown in the example, vertices 2 2 2 , 6 6

    2024年02月22日
    浏览(42)
  • 贪心找性质+dp表示+矩阵表示+线段树维护:CF573D

    比较套路的题目 首先肯定贪心一波,两个都排序后尽量相连。我一开始猜最多跨1,但其实最多跨2,考虑3个人的情况: 我们发现第3个人没了,所以可以出现跨2的情况 然后直接上dp,由 i − 1 , i − 2 , i − 3 i-1,i-2,i-3 i − 1 , i − 2 , i − 3 转移过来。 然后这显然可以拿矩阵表

    2024年02月07日
    浏览(37)
  • 【学习笔记】CF576D Flights for Regular Customers

    不同于传统的最短路,当我们走到一个节点的时候,还要记录此时经过的边数才能完成转移。但是第二维太大了,太抽象了! 看到 m m m 这么小,很难不想到离散化。那么设 f i , j f_{i,j} f i , j ​ 表示当第 i i i 条边出现时,在节点 j j j 是否可行,注意这是 01 01 01 状态。转移非

    2024年02月12日
    浏览(31)
  • 【学习笔记】CF582D Number of Binominal Coefficients

    注意 P P P 事实上不会影响复杂度,因为关于组合数,我们有一个非常经典的结论: ( n + m m ) binom{n+m}{m} ( m n + m ​ ) 包含的 P P P 的幂的次数等于 n n n 和 m m m 在 P P P 进制下做加法的进位次数。这样,我们只需要关心进位的次数,而不必知道每一位具体是多少。 这个结论的证

    2024年02月12日
    浏览(30)
  • 【学习笔记】CF1835D Doctor‘s Brown Hypothesis

    有点难😅 发现 x , y x,y x , y 在一个强连通块内,这样一定有环🤔 发现可以找到强连通块内所有环长度的 gcd ⁡ gcd g cd ,这样从 x x x 到 y y y 的所有路径的长度都模这个数同余,又因为 K K K 非常大,所以我们总可以遍历整个强连通块并走若干个环,因此只需要从 x x x 到 y y

    2024年02月09日
    浏览(32)
  • iOS_灵动岛<Dynamic Island>

    苹果在 iPhone 14 Pro 及 iPhone 14 Pro MAX 上推出了灵动岛。灵动岛可以通过点按、长按、轻扫来进行交互,最多支持两个应用同时“登岛”。 灵动岛全称 Dynamic Island,作为 iOS 中实时活动(Live Activities)功能的一部分,用来展示需要实时更新的消息。 展现形式 展现形式有三种:

    2024年02月12日
    浏览(35)
  • 如何识别手机是否有灵动岛(dynamic island)

    如何识别手机是否有灵动岛(dynamic island) 灵动岛是苹果2022年9月推出的iPhone 14 Pro、iPhone 14 Pro Max首次出现,操作系统最低是iOS16.0。带灵动岛的手机在竖屏时顶部工具栏大于等于51像素。

    2024年02月14日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包