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的更多相关文章

  1. Codeforces 603E Pastoral Oddities

    传送门:http://codeforces.com/problemset/problem/603/E [题目大意] 给出$n$个点,$m$个操作,每个操作加入一条$(u, v)$长度为$l$的边. 对 ...

  2. [转帖]IBM POWER系列处理器的前世今生

    IBM POWER系列处理器的前世今生 Power是Power Optimization With Enhanced RISC的缩写,是由IBM开发的一种RISC指令集架构(ISA). IBM的很多服 ...

  3. 转帖 IBM要推POWER9,来了解一下POWER处理器的前世今生

    https://blog.csdn.net/kwame211/article/details/76669555 先来说一下最新的POWER 9 在Hot Chips会议上首次提到的IBM Power ...

  4. VINS(二)Feature Detection and Tracking

    系统入口是feature_tracker_node.cpp文件中的main函数 1. 首先创建feature_tracker节点,从配置文件中读取信息(parameters.cpp),包括: ROS中 ...

  5. NOIP2017提高组 模拟赛13(总结)

    NOIP2017提高组 模拟赛13(总结) 第一题 函数 [题目描述] [输入格式] 三个整数. 1≤t<10^9+7,2≤l≤r≤5*10^6 [输出格式] 一个整数. [输出样例] 2 2 ...

随机推荐

  1. 批量注释LOG

    sed -i "s/LOG/\/\/ LOG/g" `grep LOG\(TRACE\) -rl .`

  2. inflate(int resource, ViewGroup root, boolean attachToRoot)见解

    /** * Inflate a new view hierarchy from the specified xml resource. Throws * {@link InflateException ...

  3. 小白学习Spark系列五:scala解析多级json格式字符串

    一.背景 处理json格式的字符串,key值一定为String类型,但value不确定是什么类型,也可能嵌套json字符串,以下是使用 JSON.parseFull 来解析多层json. 二.实例代码 ...

  4. javascript 闭包笔记

      先来解释一下闭包: 1.闭包就是函数嵌套函数 2.内部函数可以引用外部函数的参数和变量 3.参数和变量不会被垃圾回收机制所收回( 垃圾回收机制就是用完变量之后就在内存中释放 ) 使用闭包的好处: ...

  5. hdu6096 String

    String Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others) Problem De ...

  6. 清北学堂模拟赛d6t4 数组异或

    分析:直接O(n^3)做是只有50分的,可以加一点小小的优化,就是c[k]可以从c[k-1]得到,但是还是只有60分,从宏观意义上是不能继续优化了.对于这类涉及到位运算的性质的题目,将每个数转化成二进 ...

  7. 无管理员帐号的WIN7,如果使用自己的JDK版本?

    因为公司的电脑只有普通权限, 而且JDK版本低了. 那我只好用BAT脚本来导入自己的环境啦,毕竟每次在CMD窗口输入太繁琐. set JAVA_HOME=D:\JDK8 set CLASSPATH=D ...

  8. Spring Data Jpa-动态查询条件

    /** * * 查看日志列表-按照时间倒序排列 * * @author: wyc * @createTime: 2017年4月20日 下午4:24:43 * @history: * @return L ...

  9. Spring MVC-视图解析器(View Resolverr)-多重解析器(Multiple Resolver)示例(转载实践)

    以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_multiple_resolver_mapping.htm 说明:示例基于Spri ...

  10. [Javascript] AbortController to cancel the fetch request

    We are able to cancel the fetch request by using AbortController with RxJS Observable. return Observ ...