603E
LCT维护MST+子树信息
看了好长时间题解
editorial
结论:像做最小生成树一样,当每个连通块都是偶数个点就停下来。
每次复杂度mlogm
口胡
首先我们发现奇数个点是不满足每个点度数为奇数,因为一条边贡献两个度数,所以度数一定是偶数,但是奇数个点每个点奇数度度数总和是奇数,所以点数一定是偶数。
但是这样不足以解决问题。于是我们转化一下,如果一个连通块有偶数个点,那么这个连通块一定能满足条件。这里要注意,是满足条件,但是我们维护的东西并不满足条件。我们只维护最小生成森林,这样是不保证度数是奇数的,但是如果在森林上删去一些边,肯定能满足。既然多出来了一些边,怎么查找答案呢?我们每次加边,如果两个顶点不连通,那么我们连接,同时统计奇数个顶点的连通块,如果联通,那么我们删去形成的环上最大的边。然后把插入的边放进set里。每次查找,我们按边权从大到小检查,看这条边能否删去,能删去的条件是删掉这条边后两个连通块的点数都为偶数。删到不能删停下来。如果删掉一条边分裂成两个奇数大小的连通块,那么肯定是不满足条件的。这里就是解法的巧妙所在,我们保留一些可能没用的边,也不在乎性质,只有删边的时候才考虑。
然后还要维护子树信息。lct一般只能维护链上信息,但是我们发现,只有access和link和cut会改变子树之间的关系,那么我们就在这两个时候维护点权。(这里不是很清楚)
每次查询size的时候就把这个点转到根,查询即可。
好久没写lct都快忘了
#include<bits/stdc++.h>
using namespace std;
const int N = ;
struct edge {
int u, v, w, id;
edge(int u = , int v = , int w = , int id = ) : u(u), v(v), w(w), id(id) { }
bool operator < (edge e) const
{
return w == e.w ? id < e.id : w > e.w;
}
};
vector<edge> ed;
set<edge> s;
int n, m, o;
namespace lct
{
int top;
int fa[N], child[N][], size[N], v[N], tag[N], st[N], mx[N], id[N];
bool isroot(int x) { return !fa[x] || (child[fa[x]][] != x && child[fa[x]][] != x); }
void update(int x)
{
size[x] = size[child[x][]] + size[child[x][]] + v[x];
mx[x] = id[x];
if(ed[mx[child[x][]]].w > ed[mx[x]].w) mx[x] = mx[child[x][]];
if(ed[mx[child[x][]]].w > ed[mx[x]].w) mx[x] = mx[child[x][]];
}
void pushdown(int x)
{
if(!tag[x]) return;
tag[child[x][]] ^= ;
tag[child[x][]] ^= ;
swap(child[x][], child[x][]);
tag[x] ^= ;
}
void zig(int x)
{
int y = fa[x];
fa[x] = fa[y];
if(!isroot(y)) child[fa[x]][child[fa[x]][] == y] = x;
child[y][] = child[x][];
fa[child[x][]] = y;
fa[y] = x;
child[x][] = y;
update(y);
update(x);
}
void zag(int x)
{
int y = fa[x];
fa[x] = fa[y];
if(!isroot(y)) child[fa[x]][child[fa[x]][] == y] = x;
child[y][] = child[x][];
fa[child[x][]] = y;
fa[y] = x;
child[x][] = y;
update(y);
update(x);
}
void splay(int x)
{
top = ;
st[++top] = x;
for(int now = x; !isroot(now); now = fa[now]) st[++top] = fa[now];
for(int i = top; i; --i) pushdown(st[i]);
while(!isroot(x))
{
int y = fa[x], z = fa[y];
if(isroot(y))
{
child[y][] == x ? zig(x) : zag(x);
break;
}
else if(child[y][] == x && child[z][] == y) { zig(y); zig(x); }
else if(child[y][] == x && child[z][] == y) { zag(y); zag(x); }
else if(child[y][] == x && child[z][] == y) { zag(x); zig(x); }
else if(child[y][] == x && child[z][] == y) { zig(x); zag(x); }
}
}
void access(int x)
{
for(int y = ; x; y = x, x = fa[x])
{
splay(x);
v[x] -= size[y];
v[x] += size[child[x][]];
child[x][] = y;
update(x);
}
}
void rever(int x)
{
access(x);
splay(x);
tag[x] ^= ; //x本来是最深的,反转深度
}
void link(int x, int y)
{
rever(x);
fa[x] = y;
v[y] += size[x];
}
void cut(int x, int y)
{
rever(x); //u是最浅的
access(y);
splay(y);
fa[x] = child[y][] = ;
v[y] -= size[x];
update(y);
}
int find(int x)
{
access(x);
splay(x);
while(child[x][]) x = child[x][];
return x;
}
int q(int x)
{
rever(x);
return size[x];
}
} using namespace lct;
void add_edge(edge e)
{
if(q(e.u) & && q(e.v) & ) o -= ;
id[e.id + n] = e.id;
mx[e.id + n] = e.id;
link(e.u, e.id + n);
link(e.v, e.id + n);
}
int delete_edge(edge e)
{
cut(e.u, e.id + n);
cut(e.v, e.id + n);
if(q(e.u) & && q(e.v) & ) o += ;
return !(q(e.u) & );
}
int max_cost()
{
if(o) return -;
while(delete_edge(*s.begin())) s.erase(*s.begin());
add_edge(*s.begin());
return (*s.begin()).w;
}
int find_max(int u, int v)
{
rever(u);
access(v);
splay(v);
return mx[v];
}
void new_edge(edge e)
{
e.id = ed.size();
ed.push_back(e);
if(find(e.u) == find(e.v))
{
int id = find_max(e.u, e.v);
if(ed[id].w <= e.w) return;
delete_edge(ed[id]);
}
add_edge(e);
s.insert(e);
}
int main()
{
scanf("%d%d", &n, &m);
o = n;
ed.push_back(edge(, , , ));
for(int i = ; i <= n; ++i) v[i] = ;
for(int i = ; i <= m; ++i)
{
edge e;
scanf("%d%d%d", &e.u, &e.v, &e.w);
new_edge(e);
printf("%d\n", max_cost());
}
return ;
}
603E的更多相关文章
- Codeforces 603E Pastoral Oddities
传送门:http://codeforces.com/problemset/problem/603/E [题目大意] 给出$n$个点,$m$个操作,每个操作加入一条$(u, v)$长度为$l$的边. 对 ...
- [转帖]IBM POWER系列处理器的前世今生
IBM POWER系列处理器的前世今生 Power是Power Optimization With Enhanced RISC的缩写,是由IBM开发的一种RISC指令集架构(ISA). IBM的很多服 ...
- 转帖 IBM要推POWER9,来了解一下POWER处理器的前世今生
https://blog.csdn.net/kwame211/article/details/76669555 先来说一下最新的POWER 9 在Hot Chips会议上首次提到的IBM Power ...
- VINS(二)Feature Detection and Tracking
系统入口是feature_tracker_node.cpp文件中的main函数 1. 首先创建feature_tracker节点,从配置文件中读取信息(parameters.cpp),包括: ROS中 ...
- NOIP2017提高组 模拟赛13(总结)
NOIP2017提高组 模拟赛13(总结) 第一题 函数 [题目描述] [输入格式] 三个整数. 1≤t<10^9+7,2≤l≤r≤5*10^6 [输出格式] 一个整数. [输出样例] 2 2 ...
随机推荐
- ASP.NET MVC 二维码生成(ThoughtWorks.QRCode)
原文地址http://www.cnblogs.com/jys509/p/4592539.html
- Tcl之Lab1
Task 1. Use help 1) What is the default switch for the redirect command? -file help -v redirect # or ...
- =new、=null、.clear()、system.gc()的区别
开发经验告诉我 = new是指向另一个地址空间 =null对象被回收 .clear()对象被清空,但是仍然指向原来的地址空间 这三种方式都并没有真正的清理内存 只有system.gc()是直接清理,但 ...
- Python-暑期实训day 1
python基础: 一 编程语言 什么是编程语言? 上面提及的能够被计算机所识别的表达方式即编程语言,语言是沟通的介质,而编程语言是程序员与计算机沟通的介质.在编程的世界里,计算机更像是人的奴隶,人类 ...
- Python3爬取前程无忧数据分析工作并存储到MySQL
1.导入包import requests #取数from lxml import etree #用xpath解析import pymysql #连接数据库import chardet #自动获取编码2 ...
- vim使用配置-python
安装vundle git clone https://github.com/gmarik/Vundle.vim.git ~/.vim/bundle/Vundle.vim 添加配置文件 vim ~/.v ...
- win10 Ubuntu子系统安装&odoo10社区版安装
参考文档: http://www.cnblogs.com/odoouse/p/5995603.html https://www.jianshu.com/p/58090215bda8 一.win10 U ...
- 第一节:初识pandas之Series(上)
Series线性的数据结构, 也是一个一维数组. 声明:本人Python小白,以下代码只是个人学习的过程,仅仅记录一下学习的点点滴滴,若有错误,还望指正. (注:该代码均在jupyter notebo ...
- Spring 源代码学习(一)
一 .Spring容器最基本的功能 1. 读取配置文件 2. 校验配置文件的正确性 3. 将配置文件信息加载到内存 4. 通过反射实例化bean对象 5. 构建系统 二 .核心类关系图 图1-1 D ...
- Codeforces Problem 778B Bitwise Formula
题目链接:http://codeforces.com/contest/779/problem/E 题意:有n个变量都可以用m位二进制数表示,这n个数的value将以两种格式中的一种给出 1.变量名, ...