bzoj2594水管局长数据加强版题解(未完待续)

  • 题目大意

    给一张带权无向图,无重边和自环,有如下操作:

    删除某条边,保证这条边在删除前一定存在,并且不破坏原图连通性;

    询问两点之间所有路径中最小权值的最大值是多少;

  • 题解

    问题的答案显然在原图的最小生成树上,于是本题就变成了动态维护删边最小生成树。

    然而LinkCutTree维护最小生成树时并不支持删边操作,所以要离线处理,先删掉该删掉的边,再求最小生成树,把所有操作倒过来用LCT维护。

  • 如何用LCT维护动态添边最小生成树

    设原图中有n个点,m条边;

    把每条边视为一个点,编号为n+1,n+2,?,n+m,权值为其边权,初始化边权最大值为自己的边权;

    把原图中每个点的权值设成0;

    求最小生成树,每添一条边时,设这条边连接x和y,这条边编号为k。直接把x和k连起来,y和k也连起来。

  • 未完待续
  • Code
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 100005
#define maxm 1000005
#define nil T[0]
using namespace std;
int n, m, q;

struct edge
{
    bool del;
    int id, x, y, w;
    edge(bool del = false, int id = 0, int x = 0, int y = 0, int w = 0) :
        id(id), x(x), y(y), w(w) {}
}E[maxm];
bool cmpw(const edge &a, const edge &b)
{
    return a.w < b.w;
}
bool cmpdic(const edge &a, const edge &b)
{
    return a.x < b.x || (a.x == b.x && a.y < b.y);
}
bool cmpid(const edge &a, const edge &b)
{
    return a.id < b.id;
}

struct node *T[maxm + maxn + maxn], *S[maxm + maxn + maxn];
struct node
{
    bool rev;
    int id, val;
    node *fa, *lc, *rc, *mx;
    node(bool rev = false, int id = 0, int val = 0,
         node *fa = nil, node *lc = nil, node *rc = nil, node *mx = nil)
    :    rev(rev), id(id), val(val),
         fa(fa), lc(lc), rc(rc), mx(mx) {}
    inline void update()
    {
        mx = this;
        if(lc -> mx -> val > mx -> val) mx = lc -> mx;
        if(rc -> mx -> val > mx -> val) mx = rc -> mx;
    }
    inline void pushdown()
    {
        if(rev)
        {
            rev = false;
            lc -> rev ^= 1; rc -> rev ^= 1;
            swap(lc, rc);
        }
    }
};
void zig(node *x)
{
    node *y = x -> fa;
    y -> lc = x -> rc;
    x -> rc -> fa = y;
    x -> rc = y;
    x -> fa = y -> fa;
    if(y == y -> fa -> lc) y -> fa -> lc = x;
    else if(y == y -> fa -> rc) y -> fa -> rc = x;
    y -> fa = x;
    y -> update();
}
void zag(node *x)
{
    node *y = x -> fa;
    y -> rc = x -> lc;
    x -> lc -> fa = y;
    x -> lc = y;
    x -> fa = y -> fa;
    if(y == y -> fa -> lc) y -> fa -> lc = x;
    else if(y == y -> fa -> rc) y -> fa -> rc = x;
    y -> fa = x;
    y -> update();
}
void splay(node *x)
{
    int top = 0;
    S[top++] = x;
    for(node *i = x; i == i -> fa -> lc || i == i -> fa -> rc; i = i -> fa)
    {
        S[top++] = i -> fa;
    }
    while(top--) S[top] -> pushdown();
    node *y = nil, *z = nil;
    while(x == x -> fa -> lc || x == x -> fa -> rc)
    {
        y = x -> fa; z = y -> fa;
        if(x == y -> lc)
        {
            if(y == z -> lc) zig(y);
            zig(x);
        }
        else
        {
            if(y == z -> rc) zag(y);
            zag(x);
        }
    }
    x -> update();
}
inline void access(node *x)
{
    for(node *y = nil; x != nil; y = x, x = x -> fa)
    {
        splay(x);
        x -> rc = y;
        x -> update();
    }
}
inline void makeroot(node *x)
{
    access(x); splay(x); x -> rev ^= 1;
}
inline void lnk(node *x, node *y)
{
    makeroot(x);
    x -> fa = y;
}
inline void cut(node *x, node *y)
{
    makeroot(x);
    access(y); splay(y);
    x -> fa = y -> lc = nil;
    y -> update();
}
inline node* query(node *x, node *y)
{
    makeroot(x);
    access(y); splay(y);
    return y -> mx;
}

int ufs[maxn];
inline int find(int x) { return x == ufs[x] ? x : find(ufs[x]); }

int find(int x, int y)
{
    int l = 1, r = m, mid;
    while(l <= r)
    {
        mid = l + r >> 1;
        if(E[mid].x < x || (E[mid].x == x && E[mid].y < y)) l = mid + 1;
        else if(E[mid].x == x && E[mid].y == y) return mid;
        else r = mid - 1;
    }
}

struct opt
{
    int id, k, x, y, ans;
    opt(int id = 0, int k = 0, int x = 0, int y = 0, int ans = 0) :
        id(id), k(k), x(x), y(y), ans(ans) {}
} sta[maxn];

inline void read(int &a)
{
    char ch = getchar();
    a = 0;
    while(ch < ‘0‘ || ch > ‘9‘) ch = getchar();
    while(ch >= ‘0‘ && ch <= ‘9‘)
    {
        a = a * 10 + ch - 48;
        ch = getchar();
    }
}
inline void write(int a)
{
    int top = 0, ch[30];
    do
    {
        ch[top++] = a % 10 + 48;
        a /= 10;
    } while(a > 0);
    while(top--) putchar(ch[top]);
    putchar(‘\n‘);
}
void init()
{
#ifndef ONLINE_JUDGE
    freopen("2594i.txt", "r", stdin);
    freopen("2594o.txt", "w", stdout);
#endif
    int a, b, c;
    read(n); read(m); read(q);
    nil = new node(); *nil = node();
    for(int i = 1; i <= n + m + 100; ++i) T[i] = new node(false, i);
    for(int i = 1; i <= n; ++i) ufs[i] = i;
    for(int i = 1; i <= m; ++i)
    {
        scanf("%d%d%d", &E[i].x, &E[i].y, &E[i].w);
        if(E[i].x > E[i].y) swap(E[i].x, E[i].y);
    }
    sort(E + 1, E + m + 1, cmpw);
    for(int i = 1; i <= m; ++i)
    {
        E[i].id = i;
        T[n + i] -> val = E[i].w;
        T[n + i] -> mx = T[n + i];
    }
    sort(E + 1, E + m + 1, cmpdic);
    for(int i = 1; i <= q; ++i)
    {
        read(sta[i].k); read(sta[i].x); read(sta[i].y);
        if(sta[i].k == 2)
        {
            if(sta[i].x > sta[i].y) swap(sta[i].x, sta[i].y);
            int tmp = find(sta[i].x, sta[i].y);
            E[tmp].del = true; sta[i].id = E[tmp].id;
        }
    }
    sort(E + 1, E + m + 1, cmpid);
}
void work()
{
    for(int i = 1, tot = 0; i <= m && tot < n - 1; ++i)
    {
        if(!E[i].del)
        {
            int tmpu = find(E[i].x), tmpv = find(E[i].y);
            if(tmpu != tmpv)
            {
                ufs[tmpu] = tmpv;
                lnk(T[E[i].x], T[i + n]);
                lnk(T[E[i].y], T[i + n]);
                ++tot;
            }
       }
    }
    for(int i = q; i > 0; --i)
    {
        if(sta[i].k == 1)
        {
            node *p = query(T[sta[i].x], T[sta[i].y]);
            sta[i].ans = p -> val;
        }
        else
        {
            node *p = query(T[sta[i].x], T[sta[i].y]);
            if(E[sta[i].id].w < p -> val)
            {
                cut(T[E[p -> id - n].x], p);
                cut(T[E[p -> id - n].y], p);
                lnk(T[sta[i].x], T[sta[i].id + n]);
                lnk(T[sta[i].y], T[sta[i].id + n]);
            }
        }
    }
    for(int i = 1; i <= q; ++i) if(sta[i].k == 1)
    {
        write(sta[i].ans);
    }
    for(int i = 0; i <= n + m + 100; ++i)
    {
        delete T[i];
        T[i] = NULL;
    }
}
int main()
{
    init();
    work();
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-23 23:03:18

bzoj2594水管局长数据加强版题解(未完待续)的相关文章

BZOJ2594水管局长数据加强版

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

bzoj-2594 水管局长数据加强版

题意: 给出一个n个点m条边的无向图,边上有权值: Q次询问,每次有两种操作: 1.求x,y两点路径上的最大值的最小值: 2.删除一条边: 保证删除的边存在,保证图时刻连通,保证不会出现重边和自环: n≤100000,m≤1000000,Q≤100000: 题解: 这是一个动态图问题,但是由于询问操作的特殊性,我们也可以转化到树上做: 仔细看看不就是带删边的货车运输吗! 那么用LCT来维护最小生成树查询操作1就可以了: 但是LCT维护最小生成树是不能删边的: 考虑倒着处理询问,删边就成了加边:

[bzoj2594][Wc2006]水管局长数据加强版

论蒟蒻的自我修养T_T.. 和noi2014魔法森林基本一样...然而数据范围大得sxbk...100w你告诉我(n+m)log(n+m)可过?[掀桌] 蒟蒻又蠢了..复杂度应该是O((n+q)log(n+m))吧.. 一开始数组开太小re了两发(要开到maxn+maxm),然后又开太大mle一发,然后无限tle...把记录类型全改成数组还是tle.... 最后把非lct部分改得和黄学长全部一样终于20+s卡过去了......... 然后发现自己原来是有个地方写萎了..一开始把没被删的边做kru

【BZOJ 2594】 [Wc2006]水管局长数据加强版

2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MB Submit: 1138  Solved: 364 [Submit][Status] Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等

bzoj 2594: [Wc2006]水管局长数据加强版 动态树

2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MBSubmit: 934  Solved: 291[Submit][Status] Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径

BZOJ_2594_[Wc2006]水管局长数据加强版_LCT

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

BZOJ 2594: [Wc2006]水管局长数据加强版(kruskal + LCT)

Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了.嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项. 在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗.消毒等等.嘟嘟在

[BZOJ2594] [Wc2006]水管局长数据加强版(LCT + kruskal + 离线)

传送门 WC这个题真是丧心病狂啊,就是想学习一下怎么处理边权,给我来了这么一个破题! ORZ hzwer 临摹黄学长代码233 但还是复杂的一匹 理一下思路吧 题目大意:给定一个无向图,多次删除图中的某一条边,求两点间路径最大值的最小值 求两点间的路径最大值的最小值的话,可以求最小生成树,那么这个值就是最小生成树上两点间路径上的最大值 但是题目要求是删除边,LCT维护最小生成树不支持删边操作,那么就离线处理,倒着加边,用LCT维护. 就是这个离线处理是最恶心的. 来说说如何处理边权,把边也抽象成

【bzoj2594】[Wc2006]水管局长数据加强版

真是神题 当时调了几天没调出来 后来没管了 当时把fread去掉就TLE,加上就RE 一直在底下跟网上的程序拍,尝试各种优化常数都没用 拍出几组不一样的,发现我是对的,醉了,网上那个是怎么过的 记一下这蛋疼的代码 1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cstdio> 6 #include<ma