codeforces1139C. Edgy Trees 并查集

题目传送门 ┗|`O′|┛ 嗷~~

给你一个树,树的每条边都有颜色,且仅有红黑两种颜色,现有如下三条要求,现在找出所有能满足要求的集合。

  1. 我们将在树上走一条路径(可能多次访问相同的边/顶点),从a1开始到ak结束。
  2. 从a1开始,然后使用a1和a2之间的最短路径转到a2,然后以类似的方式转到a3,依此类推,直到你走到ak-1和ak之间的最短路径。
  3. 如果你在这个过程中至少走过一条黑色边缘,那么顺序是好的。
    翻译结果来自谷歌翻译

倒着求,求只经过红边的,并查集合并,快速幂算数。
在建立图之后,我们可以知道有哪些点是仅通过红边就能到达的,并将仅通过红边就能到达的点归到一个集合中,假设这个集合中有X个点,那么就可以有Xk个集合不符合上述要求,遍历所有仅通过红边相连的点集,求所有不符合要求的集合的个数,再从Nk中减去这些不符合要求的情况就是所求的答案。

下面是夹带私货时候:推荐一波四月新番—皿三味,虽然看第一集的时候真的被这沙雕剧情和各种牙白台词雷到了。因为第一次看的时候跳了op,这几天又看了一遍,貌似还是穿越拯救地球的路线,这难道又是破石头门的选择???但是沙雕归沙雕,这个番动作分镜超级流畅,就是剧情太迷,据说要到第六集才能看懂,我觉得还是很值的期待的,毕竟原几老贼的操作,还是现在好好珍惜这沙雕剧情吧,只不定哪一集过后就靠刀片发家致富了。。。


#include <stdio.h>
#include <climits>
#include <cstring>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <utility>
#include <vector>
#include <string>

#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return

#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;

int N,K;
int dsu[maxn],num[maxn];
ll quickPow(int base,int Pow);
inline int seekRoot(int x);
int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    cin>>N>>K;
    ll all=quickPow(N,K);
    rep(i,1,N+1){
        num[i]=1;
        dsu[i]=i;
    }

    int commonA,commonB,kind;
    rep(i,1,N){
        cin>>commonA>>commonB>>kind;
        if(kind==1)
            continue;
        int rootA=seekRoot(commonA);
        int rootB=seekRoot(commonB);
        dsu[rootA]=rootB;
        num[rootB]+=num[rootA];
    }

    ll sub;
    rep(i,1,N+1){
        if(dsu[i]==i){
            sub=quickPow(num[i],K);
            all=(all+mod-sub)%mod;
        }
    }

    cout<<all<<endl;

    re 0;
}
ll quickPow(int base,int Pow){
    ll ans=1,temp=base;

    while(Pow){
        if(Pow%2){
            ans=(ans*temp)%mod;
            Pow--;
        }

        temp=(temp*temp)%mod;
        Pow/=2;
    }

    re ans;
}
inline int seekRoot(int x){
    if(dsu[x]==x)
        re x;
    else
        re dsu[x]=seekRoot(dsu[x]);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值