首页 > 其他分享 >[JOISC 2014] 電圧 题解

[JOISC 2014] 電圧 题解

时间:2023-09-24 15:55:58浏览次数:45  
标签:tmp fa int 题解 top dsu JOISC siz 2014

[JOISC 2014] 電圧 题解

赛时都想到了我也不知道为啥自己没敢写

首先题意可以转化为,我们去掉一个边后,剩下的图可以黑白染色,同时保证去掉的边两端的点颜色相同,问这样的边数。换句话说,去掉一条边后,剩下的图应该是一个二分图。

然后我们很容易想到线段树分治来处理这种问题。每次只有一条边被删掉,那我们可以令第 \(i\) 条边的存在范围变成 \([1, i-1]\) 和 \([i+1, m]\),这样在时刻 \(i\),就是在验证删掉第 \(i\) 条边是否合法了。剩下的就是线段树分治板子了。

当然,我们还得验证去掉的边两端可以染成一种颜色。我们用扩展域并查集来做,只需判断一下 \(u\) 和 \(v + n\) 是否在一个集合中就行了。如果在一个集合中,则说明 \(u, v\) 必须异色;否则要么 \(u, v\) 不在一个连通块内,要么就是在一个联通块内但是同色。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+100, M = 2e5+10;

int read() {
    int x = 0; char ch = getchar();
    while(ch<'0' || ch>'9') ch = getchar();
    while(ch>='0'&&ch<='9') x = x*10+(ch-48), ch = getchar();
    return x;
}
//断开每一条边判断是否为二分图 -> 一条边存在于 1 - i-1, i+1 - n
int n, m;
struct Edge{
    int u, v;
}e[M];

struct xwx{
    int son, fa, val;
}stk[M<<1];
int top;
struct DSU{
    int fa[N<<1], siz[N<<1]; 
    void init() {
        for(int i = 1; i<=n*2; ++i) {
            fa[i] = i, siz[i] = 1;
        }
    }
    int find(int x) {
        while(x != fa[x]) x = fa[x];
        return x;
    }
    void merge(int x, int y) {
        x = find(x), y = find(y);
        if(x == y) {
            return;
        }
        if(siz[x] > siz[y]) swap(x, y);
        fa[x] = y;
        siz[y]+=siz[x];
        stk[++top] = (xwx) {x, y, siz[x]};
        return;
    }
}dsu;

int ans;
struct SegmentTree{
    vector<int> tree[M<<2];
    #define ls tr<<1
    #define rs tr<<1 | 1
    void modify(int tr, int L, int R, int lq, int rq, int id) {
        if(lq == L && R == rq) {
            tree[tr].push_back(id);
            return;
        }
        int mid = (L+R)>>1;
        if(lq <= mid) modify(ls, L, mid, lq, min(rq, mid), id);
        if(mid < rq) modify(rs, mid+1, R, max(mid+1, lq), rq, id);
    }
    void solve(int tr, int L, int R, bool flag) {
        int u, v;
        
        int st = top;
        for(int id : tree[tr]) {
            u = e[id].u, v = e[id].v;
            dsu.merge(u, v + n);
			dsu.merge(v, u + n);
			if(dsu.find(u) == dsu.find(v)) flag = 0;
        }
        if(L == R) {
            if(flag) {
                u = e[L].u, v = e[L].v;
                if(dsu.find(u) != dsu.find(v+n)) ++ans;
            }
            while(top > st) {
               xwx tmp = stk[top];
                dsu.fa[tmp.son] = tmp.son;
                dsu.siz[tmp.fa] -= tmp.val;
                --top;
            }
            return;
        }
        int mid = (L+R)>>1;
        solve(ls, L, mid, flag);
        solve(rs, mid+1, R, flag);
        while(top > st) {
            xwx tmp = stk[top];
            dsu.fa[tmp.son] = tmp.son;
            dsu.siz[tmp.fa] -= tmp.val;
            --top;
        }
    }
}seg;
int main() {
    n = read(), m = read();
    for(int i = 1; i<=m; ++i) {
        e[i] = (Edge){read(), read()};
    }
    dsu.init();
    for(int i = 1; i<=m; ++i) {
        if(i > 1) seg.modify(1, 1, m, 1, i-1, i);
        if(i < m) seg.modify(1, 1, m, i+1, m, i);
    }
    seg.solve(1, 1, m, 1);
    printf("%d\n", ans);
    return 0;
}

标签:tmp,fa,int,题解,top,dsu,JOISC,siz,2014
From: https://www.cnblogs.com/frostwood/p/17726078.html

相关文章

  • 题解
    题目大意有\(n\)个杯子,第\(i\)个杯子里装有\(W_i\)升水,且有\(n\)对正整数\(l_i,r_i\)。Yuri和Muri两人在玩一个游戏:两人轮流进行操作,最先不能进行操作者输。一次操作定义为:操作者选择一个杯子\(i\),从中喝掉\(x_i\)升水。对于两个人,都要满足\(x_i\in[l_i,\min(r_......
  • 【POJ 3253】Fence Repair 题解(贪心算法+优先队列+哈夫曼树)
    农夫约翰想修理牧场周围的一小段围栏。他测量了围栏,发现他需要N(1≤N≤20000)块木板,每块木板都有一定的整数长度Li(1≤Li≤50000)单位。然后,他购买了一块长度刚好足以锯入N块木板的长木板(即,其长度为Li长度的总和)。FJ忽略了“切口”,即锯切时锯屑损失的额外长度;你也应该忽略它。FJ伤心地......
  • S16.23.12.2. 集合论 题解
    原题连接可以发现集合对称差就是异或运算。每个点都记一个长度为值域的bitset,每一位都表示根到他有没有奇数个这个数字。那么\(a_x\)改为\(v\)的修改就变成了修改子树的所有点的bitset,每次将子树中所有点的第\(a_x\)位取反,再将第\(v\)位取反。查询就是\(u\)的\(b......
  • springBoot上传文件时MultipartFile报空问题解决方法
    1.问题描述:之前用springMVC,转成springboot之后发现上传不能用。网上参考说是springboot已经有CommonsMultipartResolver了,但是我的上传后台接收的还是null。2.解决方法加入配置类importorg.springframework.context.annotation.Bean;importorg.springframework.context......
  • AT_abc321_f [ABC321F] #(subset sum = K) with Add and Erase 题解
    AT_abc321_f[ABC321F]#(subsetsum=K)withAddandErase题解题目大意现在有一个空箱子。给你两个数\(Q,K\),然后给你\(Q\)行,每一行代表一个操作:\(+x\),即向箱子里加一个权值为\(x\)的小球。\(-x\),即从箱子里把权值为\(x\)的小球拿一个出来。保证合法,即箱子......
  • CF877F 题解
    CF877F题解更好的阅读体验提供一个扫描线+根号分治做法。首先,可以把题目的条件转化成求$sum_r-sum_{l-1}=k$的区间数。考虑扫描线,当区间的右端点从$r-1$移动到$r$时,新增的区间的左端点就是所有满足$sum_{l-1}=sum_r-k,l\ler$的$l$。这时我们对$sum_{l-1}$......
  • 【笔记】P6419 [COCI2014-2015#1] Kamp 答辩做法
    模拟赛T3,用非常答辩的做法过掉了。5k代码写完后竟只调了10分钟首先考虑指定出发点如何算答案。用一眼看出法,就是把出发点也定为必经点后,\(必经点连通距离\times2\-\出发点到某一必经点的最大距离\)。这个想法可以由P9304的思路得到。再有,要求树上所有点的答案,多半是换根......
  • 【问题解决】shell脚本执行错误 $‘\r‘:command not found
    问题原因:在Windows中,换行符是由回车符(\r)和换行符(\n)组成的,而在Unix/Linux等系统中,只使用换行符(\n)作为换行标志。当你在Unix/Linux系统上运行一个包含Windows格式换行符的脚本时,Shell会尝试解释其中的回车符,导致错误提示$‘\r’:commandnotfound。这是因为Shell将回......
  • [COCI2016-2017#4] Osmosmjerka 题解
    [COCI2016-2017#4]Osmosmjerka题解我们发现对于每个点,只有八个方向,也就是说,最终能得到的字符串只会有\(8nm\)个,那我们可以考虑把这些字符串的哈希值求出来,相同的哈希值代表选到相同字符串的一种可能,直接统计即可。现在的问题就在于,怎么快速地求出这\(8nm\)个字符串的哈希......
  • 题解 CF1257G【Divisor Set】
    problem我们说一个集合\(D\)是一个好的集合,当不存在集合中的两个不同元素\(a,b\)使得\(a\)是\(b\)的约数。给定一个超大整数的素数表示形式\(N=\prod_{i=1}^n{p_i}\),要求从它的所有因子中选择尽可能多的元素组成一个好的集合。问这个最大的size是多少,输出模99824......