603E

LCT维护MST+子树信息

看了好长时间题解

editorial

结论:像做最小生成树一样,当每个连通块都是偶数个点就停下来。

每次复杂度mlogm

口胡

首先我们发现奇数个点是不满足每个点度数为奇数,因为一条边贡献两个度数,所以度数一定是偶数,但是奇数个点每个点奇数度度数总和是奇数,所以点数一定是偶数。

但是这样不足以解决问题。于是我们转化一下,如果一个连通块有偶数个点,那么这个连通块一定能满足条件。这里要注意,是满足条件,但是我们维护的东西并不满足条件。我们只维护最小生成森林,这样是不保证度数是奇数的,但是如果在森林上删去一些边,肯定能满足。既然多出来了一些边,怎么查找答案呢?我们每次加边,如果两个顶点不连通,那么我们连接,同时统计奇数个顶点的连通块,如果联通,那么我们删去形成的环上最大的边。然后把插入的边放进set里。每次查找,我们按边权从大到小检查,看这条边能否删去,能删去的条件是删掉这条边后两个连通块的点数都为偶数。删到不能删停下来。如果删掉一条边分裂成两个奇数大小的连通块,那么肯定是不满足条件的。这里就是解法的巧妙所在,我们保留一些可能没用的边,也不在乎性质,只有删边的时候才考虑。

然后还要维护子树信息。lct一般只能维护链上信息,但是我们发现,只有access和link和cut会改变子树之间的关系,那么我们就在这两个时候维护点权。(这里不是很清楚)

每次查询size的时候就把这个点转到根,查询即可。

好久没写lct都快忘了

#include<bits/stdc++.h>
using namespace std;
const int N = 600010;
struct edge {
    int u, v, w, id;
    edge(int u = 0, int v = 0, int w = 0, int id = 0) : 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][2], size[N], v[N], tag[N], st[N], mx[N], id[N];
    bool isroot(int x) { return !fa[x] || (child[fa[x]][0] != x && child[fa[x]][1] != x); }
    void update(int x)
    {
        size[x] = size[child[x][0]] + size[child[x][1]] + v[x];
        mx[x] = id[x];
        if(ed[mx[child[x][0]]].w > ed[mx[x]].w) mx[x] = mx[child[x][0]];
        if(ed[mx[child[x][1]]].w > ed[mx[x]].w) mx[x] = mx[child[x][1]];
    }
    void pushdown(int x)
    {
        if(!tag[x]) return;
        tag[child[x][0]] ^= 1;
        tag[child[x][1]] ^= 1;
        swap(child[x][0], child[x][1]);
        tag[x] ^= 1;
    }
    void zig(int x)
    {
        int y = fa[x];
        fa[x] = fa[y];
        if(!isroot(y)) child[fa[x]][child[fa[x]][1] == y] = x;
        child[y][0] = child[x][1];
        fa[child[x][1]] = y;
        fa[y] = x;
        child[x][1] = 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]][1] == y] = x;
        child[y][1] = child[x][0];
        fa[child[x][0]] = y;
        fa[y] = x;
        child[x][0] = y;
        update(y);
        update(x);
    }
    void splay(int x)
    {
        top = 0;
        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][0] == x ? zig(x) : zag(x);
                break;
            }
            else if(child[y][0] == x && child[z][0] == y) { zig(y); zig(x); }
            else if(child[y][1] == x && child[z][1] == y) { zag(y); zag(x); }
            else if(child[y][1] == x && child[z][0] == y) { zag(x); zig(x); }
            else if(child[y][0] == x && child[z][1] == y) { zig(x); zag(x); }
        }
    }
    void access(int x)
    {
        for(int y = 0; x; y = x, x = fa[x])
        {
            splay(x);
            v[x] -= size[y];
            v[x] += size[child[x][1]];
            child[x][1] = y;
            update(x);
        }
    }
    void rever(int x)
    {
        access(x);
        splay(x);
        tag[x] ^= 1; //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][0] = 0;
        v[y] -= size[x];
        update(y);
    }
    int find(int x)
    {
        access(x);
        splay(x);
        while(child[x][0]) x = child[x][0];
        return x;
    }
    int q(int x)
    {
        rever(x);
        return size[x];
    }
} using namespace lct;
void add_edge(edge e)
{
    if(q(e.u) & 1 && q(e.v) & 1) o -= 2;
    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) & 1 && q(e.v) & 1) o += 2;
    return !(q(e.u) & 1);
}
int max_cost()
{
    if(o) return -1;
    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(0, 0, 0, 0));
    for(int i = 1; i <= n; ++i) v[i] = 1;
    for(int i = 1; i <= m; ++i)
    {
        edge e;
        scanf("%d%d%d", &e.u, &e.v, &e.w);
        new_edge(e);
        printf("%d\n", max_cost());
    }
    return 0;
}
时间: 2024-11-07 15:36:21

603E的相关文章

[Codeforces 603E]Pastoral Oddities(LCT)

[Codeforces 603E]Pastoral Oddities(LCT) 题面 图中有n个孤立点,依次向图中加入m条带权无向边.使得图中每个点的度数均为奇数的边集是合法的,其权值定义为集合中的最大边权.每次加入边后,询问权值最小的合法边集的权值,不存在合法边集时输出?1. \(n \leq 10^5,m \leq 3\times 10^5\) 分析 手玩样例可得:图存在合法边集,当且仅当每个连通块的大小为偶数 证明: 先证明充分性:假设某合法连通块大小为奇数,那么该块的总度数是奇数.但所有

Codeforces 603E Pastoral Oddities

传送门:http://codeforces.com/problemset/problem/603/E [题目大意] 给出$n$个点,$m$个操作,每个操作加入一条$(u, v)$长度为$l$的边. 对于每次操作后,求出一个边集,使得每个点度数均为奇数,且边集的最大边最小. $n \leq 10^5, m \leq 3 * 10^5$ [题解] 有结论:满足条件(每个点度数均为奇数),当且仅当每个连通块大小都是偶数(容易证明,从下往上,调整法). 那么显然可以LCT维护连通性,连通块大小以及最大边

做最懂中国程序员的开源HTML5框架

摘要:有人推崇产品,有人推崇运营,也有人推崇战略-到底该推崇什么?李智勇系统地分析了这三者之间的思路,并引用黑格尔的一句话,给出了自己的看法:在尺度中已经蕴含本质,这在产品.运营.战略的侧重上体现的非常好. 视野不拉升或者认知不深入时,就容易在盲人摸象层面上反复,看到微信火了,那就产品最重要,看到阿里火了,那就平台最重要.实际上一个比较显然的事实是,没有锥子一样的产品,那你就火不起来:不能从产品升级为平台,那就很可能活不下去.当然,有些人会说平台也是一种产品,但就和人与猴子都是灵长目,实际上仍是

自学成才 16个非常优秀的在线教育网站

摘要:有人推崇产品,有人推崇运营,也有人推崇战略-到底该推崇什么?李智勇系统地分析了这三者之间的思路,并引用黑格尔的一句话,给出了自己的看法:在尺度中已经蕴含本质,这在产品.运营.战略的侧重上体现的非常好. 视野不拉升或者认知不深入时,就容易在盲人摸象层面上反复,看到微信火了,那就产品最重要,看到阿里火了,那就平台最重要.实际上一个比较显然的事实是,没有锥子一样的产品,那你就火不起来:不能从产品升级为平台,那就很可能活不下去.当然,有些人会说平台也是一种产品,但就和人与猴子都是灵长目,实际上仍是

30个经典的网站主页模板

摘要:有人推崇产品,有人推崇运营,也有人推崇战略-到底该推崇什么?李智勇系统地分析了这三者之间的思路,并引用黑格尔的一句话,给出了自己的看法:在尺度中已经蕴含本质,这在产品.运营.战略的侧重上体现的非常好. 视野不拉升或者认知不深入时,就容易在盲人摸象层面上反复,看到微信火了,那就产品最重要,看到阿里火了,那就平台最重要.实际上一个比较显然的事实是,没有锥子一样的产品,那你就火不起来:不能从产品升级为平台,那就很可能活不下去.当然,有些人会说平台也是一种产品,但就和人与猴子都是灵长目,实际上仍是

传苹果iOS 9将重点关注系统稳定和优化

摘要:有人推崇产品,有人推崇运营,也有人推崇战略-到底该推崇什么?李智勇系统地分析了这三者之间的思路,并引用黑格尔的一句话,给出了自己的看法:在尺度中已经蕴含本质,这在产品.运营.战略的侧重上体现的非常好. 视野不拉升或者认知不深入时,就容易在盲人摸象层面上反复,看到微信火了,那就产品最重要,看到阿里火了,那就平台最重要.实际上一个比较显然的事实是,没有锥子一样的产品,那你就火不起来:不能从产品升级为平台,那就很可能活不下去.当然,有些人会说平台也是一种产品,但就和人与猴子都是灵长目,实际上仍是

构建一个属于软件开发者的键盘

摘要:有人推崇产品,有人推崇运营,也有人推崇战略-到底该推崇什么?李智勇系统地分析了这三者之间的思路,并引用黑格尔的一句话,给出了自己的看法:在尺度中已经蕴含本质,这在产品.运营.战略的侧重上体现的非常好. 视野不拉升或者认知不深入时,就容易在盲人摸象层面上反复,看到微信火了,那就产品最重要,看到阿里火了,那就平台最重要.实际上一个比较显然的事实是,没有锥子一样的产品,那你就火不起来:不能从产品升级为平台,那就很可能活不下去.当然,有些人会说平台也是一种产品,但就和人与猴子都是灵长目,实际上仍是

你的年终奖有多少?过年放几天假

摘要:有人推崇产品,有人推崇运营,也有人推崇战略-到底该推崇什么?李智勇系统地分析了这三者之间的思路,并引用黑格尔的一句话,给出了自己的看法:在尺度中已经蕴含本质,这在产品.运营.战略的侧重上体现的非常好. 视野不拉升或者认知不深入时,就容易在盲人摸象层面上反复,看到微信火了,那就产品最重要,看到阿里火了,那就平台最重要.实际上一个比较显然的事实是,没有锥子一样的产品,那你就火不起来:不能从产品升级为平台,那就很可能活不下去.当然,有些人会说平台也是一种产品,但就和人与猴子都是灵长目,实际上仍是

Android动画之仿美团加载数据等待时小人奔跑..

摘要:有人推崇产品,有人推崇运营,也有人推崇战略-到底该推崇什么?李智勇系统地分析了这三者之间的思路,并引用黑格尔的一句话,给出了自己的看法:在尺度中已经蕴含本质,这在产品.运营.战略的侧重上体现的非常好. 视野不拉升或者认知不深入时,就容易在盲人摸象层面上反复,看到微信火了,那就产品最重要,看到阿里火了,那就平台最重要.实际上一个比较显然的事实是,没有锥子一样的产品,那你就火不起来:不能从产品升级为平台,那就很可能活不下去.当然,有些人会说平台也是一种产品,但就和人与猴子都是灵长目,实际上仍是