【做题】cf603E——线段树分治

时间:2022-08-31 16:11:48

首先感谢题解小哥,他在标算外又总结了三种做法。

此处仅提及最后一种做法。

首先考虑题目中要求的所有结点度数为奇数的限制。

对于每一个联通块,因为所有结点总度数是偶数,所以总结点数也必须是偶数的。即所有联通块都要是偶数大小。

而考虑任意一个偶数大小的联通块,我们任意取它的一个生成树,然后进行如下算法:

设 1 为根结点;

按深度从大到小枚举每一个结点

若其当前度数为偶数

则断开与他的父结点的连边;

这样除根结点外的所有结点的度数都能保证为奇数,而因为总度数和为偶数,所以根结点的度数也为奇数。

因此,我们得到

存在方案使得所有结点度数为奇数 \(\iff\) 所有联通快大小为偶数。

注意到偶数加偶数还是偶数,换言之,添加多余的边是不会使答案变劣的。并且,答案是单调递减的。所以我们可以达到如下结论:

如果第\(j\)次询问的答案大于等于第\(i\)条边的边权,那么可以在处理询问区间\(\left[ i,j-1 \right]\)时直接将第\(i\)条边加上。

这样我们就可以用线段树分治。我们对询问开线段树,从后往前处理。遍历到叶结点时按边权暴力从小到大枚举边(在上一次基础上),与此同时确定了枚举到的边产生贡献的范围,用线段树实现区间修改。在遍历时需要维护支持撤销操作的并查集。这相当于是在分治的同时确定每条边的删除时间,即答案小于它的边权的时刻。

时间复杂度\(O(nlog^2n)\)。

#include <bits/stdc++.h>
using namespace std;
const int N = 300010;
int odd;
struct record {
int *p,v;
inline void rollback() {
*p = v;
}
} rec[N * 10];
int uni[N],sz[N],cnt;
int get_fa(int x) {
while (uni[x] != x)
x = uni[x];
return x;
}
void unio(int x,int y) {
x = get_fa(x);
y = get_fa(y);
if (x == y) return;
if (sz[x] > sz[y]) swap(x,y);
int tmp = (sz[x]&1) + (sz[y]&1) - ((sz[x] + sz[y])&1);
rec[++cnt] = (record) {&odd,odd};
odd -= tmp;
rec[++cnt] = (record) {&uni[x],uni[x]};
uni[x] = y;
rec[++cnt] = (record) {&sz[y],sz[y]};
sz[y] += sz[x];
}
struct data {
int a,b,v,id;
bool operator < (const data& x) const {
return v < x.v;
}
} dat[N];
vector<int> edg[N << 2];
int n,m,cur,ans[N];
void modify(int lp,int rp,int id,int x,int l,int r) {
if (lp > rp) return;
if (lp > r || rp < l) return;
if (l >= lp && r <= rp)
return (void) (edg[x].push_back(id));
int mid = (l + r) >> 1;
modify(lp,rp,id,x<<1,l,mid);
modify(lp,rp,id,x<<1|1,mid+1,r);
}
void solve(int x,int l,int r) {
int tmp = cnt;
for (int i = 0 ; i < (int)edg[x].size() ; ++ i)
unio(dat[edg[x][i]].a,dat[edg[x][i]].b);
if (l != r) {
int mid = (l + r) >> 1;
solve(x<<1|1,mid+1,r);
solve(x<<1,l,mid);
} else {
for ( ; cur <= m && odd > 0 ; ++ cur) {
if (dat[cur].id > l) continue;
unio(dat[cur].a,dat[cur].b);
modify(dat[cur].id,l-1,cur,1,1,m);
}
if (odd > 0) ans[l] = -1;
else ans[l] = dat[cur-1].v;
}
while (cnt > tmp)
rec[cnt--].rollback();
}
int main() {
int a,b,c;
scanf("%d%d",&n,&m);
odd = n;
for (int i = 1 ; i <= m ; ++ i) {
scanf("%d%d%d",&a,&b,&c);
dat[i] = (data) {a,b,c,i};
}
for (int i = 1 ; i <= n ; ++ i)
uni[i] = i, sz[i] = 1;
sort(dat+1,dat+m+1);
cur = 1;
solve(1,1,m);
for (int i = 1 ; i <= m ; ++ i)
printf("%d\n",ans[i]);
return 0;
}

小结:其实我根本不会想到糊结论……线段树分治的做法,相比LCT做法更加巧妙,利用题目的特殊性质从而简化了代码量。

【做题】cf603E——线段树分治的更多相关文章

  1. BZOJ4644&colon; 经典傻逼题【线段树分治】【线性基】

    Description 这是一道经典傻逼题,对经典题很熟悉的人也不要激动,希望大家不要傻逼. 考虑一张N个点的带权无向图,点的编号为1到N. 对于图中的任意一个点集 (可以为空或者全集),所有恰好有一 ...

  2. 【线段树分治 01背包】loj&num;6515&period; 「雅礼集训 2018 Day10」贪玩蓝月

    考试时候怎么就是没想到线段树分治呢? 题目描述 <贪玩蓝月>是目前最火爆的网页游戏.在游戏中每个角色都有若干装备,每件装备有一个特征值 $w$ 和一个战斗力 $v$ .在每种特定的情况下, ...

  3. 洛谷&period;3733&period;&lbrack;HAOI2017&rsqb;八纵八横&lpar;线性基 线段树分治 bitset&rpar;

    LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...

  4. BZOJ4025 二分图(线段树分治&plus;并查集)

    之前学了一下线段树分治,这还是第一次写.思想其实挺好理解,即离线后把一个操作影响到的时间段拆成线段树上的区间,并标记永久化.之后一块处理,对于某个节点表示的时间段,影响到他的就是该节点一直到线段树根的 ...

  5. 【BZOJ2001】&lbrack;HNOI2010&rsqb;城市建设(CDQ分治,线段树分治)

    [BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...

  6. 【BZOJ4137】火星商店问题(线段树分治,可持久化Trie)

    [BZOJ4137]火星商店问题(线段树分治,可持久化Trie) 题面 洛谷 BZOJ权限题 题解 显然可以树套树,外层线段树,内层可持久化Trie来做. 所以我们需要更加优美的做法.--线段树分治. ...

  7. &lbrack;基本操作&rsqb;线段树分治和动态dp

    不知道为什么要把这两个没什么关系的算法放到一起写...可能是都很黑科技? 1.线段树分治 例题:bzoj4026 二分图 给你一个图,资瓷加一条边,删一条边,询问当前图是不是二分图 如果用 LCT 的 ...

  8. 【Codeforces576E&lowbar;CF576E】Painting Edges(可撤销并查集&plus;线段树分治)

    题目 CF576E 分析: 从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下. 首先做这题之前推荐一道很相似的题:[BZOJ4025]二分图(可撤销并查集+线段树 ...

  9. &lbrack;BZOJ 4025&rsqb;二分图&lpar;线段树分治&plus;带边权并查集&rpar;

    [BZOJ 4025]二分图(线段树分治+带边权并查集) 题面 给出一个n个点m条边的图,每条边会在时间s到t出现,问每个时间的图是否为一个二分图 \(n,m,\max(t_i) \leq 10^5\ ...

随机推荐

  1. &lbrack;从产品角度学EXCEL 02&rsqb;-EXCEL里的树形结构

    这是<从产品角度学EXCEL>系列第三篇. 前言请看: 0 为什么要关注EXCEL的本质 1 excel是怎样运作的 或者你可以去微信公众号@尾巴说数 获得连载目录. 本文仅由尾巴本人发布 ...

  2. CSS圆角效果

    看了院子里一篇关于CSS圆角技巧的文章,试了一下,觉得很好,贴出练习的代码.优秀文章链接: http://www.cnblogs.com/luluping/archive/2010/06/26/176 ...

  3. 调试PHP错误

    error_reporting(E_ALL & ~E_NOTICE); ini_set('display_errors', "On");

  4. cacti监控jvm

    jdk环境 java version "1.6.0_37" Java(TM) SE Runtime Environment (build 1.6.0_37-b06) Java Ho ...

  5. ubuntu14&period;04&lpar;server amd64&rpar;免密码sudo

    vi /etc/sudoers.d/nopasswd4sudo 加入以下内容 用户名 ALL=(ALL) NOPASSWD : ALL

  6. The Architecture of Open Source Applications——阅读笔记part 1

    Architects look at thousands of buildings during their training, and study critiques of those buildi ...

  7. 详解 Facebook 田渊栋 NIPS2017 论文:深度强化学习研究的 ELF 平台

    这周,机器学习*会议 NIPS 2017 的论文评审结果已经通知到各位论文作者了,许多作者都马上发 Facebook/Twitter/Blog/ 朋友圈分享了论文被收录的喜讯.大家的熟人 Faceb ...

  8. &lbrack;SoapUI&rsqb; 重载JSONComparator比对JSON Response,忽略小数点后几位,将科学计数法转换为普通数字进行比对,在错误信息中打印当前循环的case number及其他附加信息

    重载JSONComparator比对JSON Response,忽略小数点后几位,将科学计数法转换为普通数字进行比对,在错误信息中打印当前循环的case number及其他附加信息 package d ...

  9. JavaScript设计模式学习之路——继承

    早在学习java的时候,就已经接触了继承,在java中因为有extends关键字,因此继承就比较简单.但是在JavaScript中,只能通过灵活的办法实现类的继承. 下面是我昨天在学习过程中,了解到的 ...

  10. tornado 之 异步非阻塞

    异步非阻塞 1.基本使用 装饰器 + Future 从而实现Tornado的异步非阻塞 import tornado.web import tornado.ioloop from tornado im ...