首页 > 其他分享 >哥大周赛题目 0-1 Tree (BFS + 并查集)

哥大周赛题目 0-1 Tree (BFS + 并查集)

时间:2022-09-29 04:33:16浏览次数:68  
标签:周赛 val int res 哥大 查集 vis ll define

上周本地比赛,老wf选手都退役了,只剩我们这些22届本科升研究生来参赛了

题目不是很难,11题,比之前的训练赛要简单很多,开场A了4题签到 + 1裸dp + 1做过 + 1xjb乱搞。结果最后一题本来没思路,但是出去上了个厕所之后回来突发奇想,用排序大法乱搞了一波,wa9,然后我接着又写了三个排序,每个都试一遍,结果莫名其妙冲过去了,最后8题结束。

然后意外的发现今年还能打,走向了未曾设想的道路,即代表学校出战,研一还继续打明年三月的regional,神奇的体验

拐回来看题,首先今天有点事,做完溜了

这题给出一棵带权无根树,每个边要么是0要么是1,问图中存在多少对点(u, v),使得u到v的路径上不存在先走1再走0, 另外(u, v)和(v, u)算两对

首先题意很清楚,我们很容易想到,全0和全1都是合法的,先走0再走1也是合法的

那么首先我们把三种情况列出来

 

 

 

然后我们再把所有全0和全1的连通分量处理出来,用并查集记录其大小,因为树的性质,所以每个子集对答案的贡献就是(size * (size - 1))

然后我们再从每个点开始bfs,看看0和哪些1边接壤了,有了上一步的处理,我们可以O(1)时间内得知相邻的点集的大小

 

 

所以每次对答案的贡献就是(size0 - 1) * (size1 - 1), -1是因为接壤的点被重复计算了,所以必须要减掉

然后注意在ll乘法的时候作为右值一定要*1ll,不然会挂

#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (3000000 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;

inline ll read() {
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > '9' || s < '0') {
        if (s == '-')sign = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9') {
        ll  x = (x << 3) + (x << 1) + s - '0';
        s = getchar();
    }
    return x * sign;
#undef getchar
}//快读
void print(ll x) {
    if (x / 10) print(x / 10);
    *O++ = x % 10 + '0';
}

void write(ll x, char c = 't') {
    if (x < 0)putchar('-'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;
}

int n, m, k;
int a[limit];
int vis[limit];
int fa[limit];
int fa2[limit];
int get_fa(int x){
    return x == fa[x] ? x : fa[x] = get_fa(fa[x]);
}
int get_fa2(int x){
    return x == fa2[x] ? x : fa2[x] = get_fa2(fa2[x]);
}
void init(){
    rep(i,1,n){
        fa[i] = i;
        fa2[i] = i;
    }
}
void merge(int x, int y){
    if(x > y)swap(x,y);
    int pa = get_fa(x);
    int pb = get_fa(y);
    fa[pb] = pa;
}
void merge0(int x, int y){
    if(x > y)swap(x,y);
    int pa = get_fa2(x);
    int pb = get_fa2(y);
    fa2[pb] = pa;
}
vector<pi(int, int)>g[limit];
void solve(){
    cin>>n;
    init();
    rep(i,1,n - 1){
        int x,y,w;
        cin>>x>>y>>w;
        g[x].push_back({y,w});
        g[y].push_back({x,w});
    }
    ll ans = 0;
    auto bfs = [&](int x, int val = 1) -> ll {
        queue<int>q;
        int res = 0;
        vis[x] = 1;
        q.push(x);
        while(q.size()){
            int u = q.front();
            if(val)merge(x, u);
            else merge0(x, u);
            q.pop();
            ++res;
            for(auto & [v, w]: g[u]){
                if(w == val and !vis[v]){
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
        return res * (res -  1);
    };
    map<int, int>one, zero;
    auto bfs2 = [&](int x) -> ll {
        set<int>s;
        queue<int>q;
        ll res = 0;
        vis[x] = 1;
        q.push(x);
        int flag = 0;
        int flag2 = 0;
        while(q.size()){
            int u = q.front();
            q.pop();
            for(auto & [v, w]: g[u]){
                if(!w and !vis[v]){
                    vis[v] = 1;
                    q.push(v);
                    flag = 1;
                }else{
                    s.insert(fa[v]);
                    flag2 = 0;
                }
            }
        }
        if(flag){
            for(auto & it : s){
                res += (1ll * zero[get_fa2(x)] - 1) * (one[get_fa(it)] - 1);
            }
        }
        return res;
    };
    rep(i,1,n){
        if(!vis[i]){
            bfs(i);
        }
    }
    fill(vis, vis + 1 + n, 0);
    rep(i,1,n){
        if(!vis[i]){
            bfs(i, 0);
        }
    }

    rep(i,1,n){
        one[get_fa(i)]++;
        zero[get_fa2(i)]++;
    }
    for(const auto & [key, val] : one){
        ans += (1ll * val * (val - 1));
    }
    for(const auto & [key, val] : zero){
        ans += (1ll * val * (val - 1));
    }
    fill(vis, vis + 1 + n, 0);
    rep(i,1,n){
        if(!vis[i]){
            ll res = bfs2(i);
            ans += 1ll * res;
        }
    }
    cout<<ans<<endl;

};
int32_t main() {
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
//    int kase;
//    cin>>kase;
//    while (kase--)
    solve();
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
    return 0;
}
AC Code

 

标签:周赛,val,int,res,哥大,查集,vis,ll,define
From: https://www.cnblogs.com/tiany7/p/16740134.html

相关文章

  • AGC016D XOR Replace(并查集)
    AGC016DXORReplace一个序列,一次操作可以将某个位置变成整个序列的异或和。问最少几步到达目标序列。\(n\le100000\)。CODE令最后一个数是初始异或和然后每次操作就......
  • 第312场周赛
    T1:简单排序,sort一下即可T2:寻找连续子数组按位与值最大前提下,最长长度。非常不明显,最大按位与就是最大值,则最长长度则连续最大值的长度最大值(md仔细分析呀)T3:寻找下标满......
  • leetcode 311场周赛总结
    1、最小偶倍数(2413)题目:给你一个正整数n,返回2和n的最小公倍数(正整数)。签到题,奇数的话就*2,偶数直接返回。classSolution{public:intsmallestEvenMultip......
  • 2022 9/23周赛丙组记录
    训练过程分析:这次比赛四道题,第一道我花了23分钟,错一次,编译错误。第二道题,我提交了两次,第一次答案错误。第三题我看不懂题目。第四题时间超限,只对了9%。两小时得了209......
  • 第308场周赛
    这次差两分钟做出最后一道题第308场周赛2389.和有限的最长子序列我用的双重循环,时间复杂度挺高的,但是蛮有意思的哈哈哈classSolution{public:vector<int>a......
  • # 87双周赛
    这次只做出了三道题6184.统计共同度过的日子数不熟悉api,没用过sscanf,在处理日期字符串的时候耽误了很多时间,最后用的substr()和stoi(stoi还是现场在网上搜的,哈哈哈)......
  • 并查集优化
    并查集及其优化并查集可以动态地连通两个点,可以非常快速判断两个点是否连通。假设存在n个节点,我们先将所有结点的leader标为自身;每次连接节点i和j时,我们可以将i......
  • Day_1(并查集朋友圈、字典序排序)
    1.并查集朋友圈:找出最多的一个圈子内有多少用户!id[](表示当前节点的父节点)nodeNum[](表示当前节点为根的那一组节点数量)importjava.util.Scanner;//并查集class......
  • acwing第67场周赛
    1.火柴棍数字原题链接:https://www.acwing.com/problem/content/4612/思路利用n根火柴拼成最大的数字数字位数越大,数字的值就越大1只用两根火柴就可以拼成,所以就看n根......
  • acwing第66场周赛
    1.判断奇偶原题链接:https://www.acwing.com/problem/content/4609/判断就就直接%2即可#include<iostream>usingnamespacestd;intmain(){strings;fo......