题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2594

题意:给出一个无向图,边有权值。定义一条路径的长度为该路径所有边的最大值。两种操作:(1)询问u到v所有路径的长度的最小值;(2)删掉某条边。

思路:

(1)将每个边也转化成一个点,比如边(1,2),转化成(1,3),(3,2)两个边;那么边权看做3的点权;1和2的点权可以看做0;

(2)反着做。首先将删掉的边都删掉,询问倒着回答,那么就成了加边。

(3)显然,路径长度就是最小生成树的最大值。因此,首先,将没有删掉的边求一次最小生成树,将最小生成树的边建立动态树。

(4)对于查询比较简单直接查就行。

(5)对于添加边(u,v),若u与v之前没有连通,则该边直接加进去就行,其实就是两个子树连在一起;否则,该边加进去之后会出现环,那么需要删掉环上的最大值的边。

struct node
{
    int Max,maxNode,val,id,isRev;
    node *c[2],*f;
    
    void reverse()
    {
        isRev^=1;
        swap(c[0],c[1]);
    }
};

node a[N],*nullNode;

void init()
{
    nullNode=new node();
    nullNode->Max=nullNode->val=nullNode->isRev=0;
    nullNode->c[0]=nullNode->c[1]=nullNode->f=nullNode;
}

void pushUp(node *x)
{
    if(x==nullNode) return;
    x->maxNode=x->id;
    x->Max=x->val;
    
    if(x->c[0]!=nullNode&&x->c[0]->Max>x->Max)
    {
        x->maxNode=x->c[0]->maxNode;
        x->Max=x->c[0]->Max;
    } 
    if(x->c[1]!=nullNode&&x->c[1]->Max>x->Max)
    {
        x->maxNode=x->c[1]->maxNode;
        x->Max=x->c[1]->Max;
    }
}

void pushDown(node *x)
{
    if(x==nullNode) return;
    if(x->isRev)
    {
        if(x->c[0]!=nullNode) x->c[0]->reverse();
        if(x->c[1]!=nullNode) x->c[1]->reverse();
        x->isRev=0;
    }
}

int isRoot(node *x)
{
    if(x->f==nullNode) return 1;
    node *p=x->f;
    return p->c[0]!=x&&p->c[1]!=x;
}

void zig(node *x)
{
    node *p=x->f,*q=p->f;
    p->c[0]=x->c[1];
    if(x->c[1]!=nullNode) x->c[1]->f=p;
    x->c[1]=p;
    p->f=x;
    x->f=q;
    if(q!=nullNode)
    {
        if(q->c[0]==p) q->c[0]=x;
        if(q->c[1]==p) q->c[1]=x;
    }
    pushUp(p);
}

void zag(node *x)
{
    node *p=x->f,*q=p->f;
    p->c[1]=x->c[0];
    if(x->c[0]!=nullNode) x->c[0]->f=p;
    x->c[0]=p;
    p->f=x;
    x->f=q;
    if(q!=nullNode)
    {
        if(q->c[0]==p) q->c[0]=x;
        if(q->c[1]==p) q->c[1]=x;
    }
    pushUp(p);
}

void splay(node *x)
{
    pushDown(x);
    while(!isRoot(x))
    {
        if(!isRoot(x->f))
        {
            pushDown(x->f->f);
            pushDown(x->f);
            pushDown(x);
            if(x->f->f->c[0]==x->f)
            {
                if(x->f->c[0]==x) zig(x->f),zig(x);
                else zag(x),zig(x);
            }
            else 
            {
                if(x->f->c[1]==x) zag(x->f),zag(x);
                else zig(x),zag(x);
            }
        }
        else
        {
            pushDown(x->f);
            pushDown(x);
            if(x->f->c[0]==x) zig(x);
            else zag(x);
        }
    }
    pushUp(x);
}

node *access(node *x)
{
    node *p=nullNode;
    while(x!=nullNode)
    {
        splay(x);
        x->c[1]=p;
        pushUp(x);
        p=x;
        x=x->f;
    }
    return p;
}

void makeRoot(int x)
{
    access(a+x);
    splay(a+x);
    a[x].reverse();
}

void join(int x,int y)
{
    makeRoot(x); access(a+y); splay(a+y);
    a[x].f=a+y;
}

void cut(int x,int y)
{
    makeRoot(x); access(a+y); splay(a+y);
    a[y].c[0]->f=nullNode;
    a[y].c[0]=nullNode;
    splay(a+y);
}

pair<int,int> query(int x,int y)
{
    makeRoot(y); access(a+x); splay(a+x);
    if(a[y].f==nullNode) return MP(-1,-1);
    access(a+x);
    node *p=a+y,*q=nullNode;
    int Max,maxNode;
    while(p!=nullNode)
    {
        splay(p);
        if(p->f==nullNode)
        {
            Max=p->val;
            maxNode=p->id;
            if(p->c[1]!=nullNode&&p->c[1]->Max>Max)
            {
                Max=p->c[1]->Max;
                maxNode=p->c[1]->maxNode;
            }
            if(q!=nullNode&&q->Max>Max)
            {
                Max=q->Max;
                maxNode=q->maxNode;
            }
            return MP(maxNode,Max);
        }
        p->c[1]=q;
        q=p;
        pushUp(q);
        p=p->f;
    }
}

int W[N];

int n,m,Q;

struct OP
{
    int u,v,op,ans;
};

OP b[100005];

int c[N][2];

int get()
{
    int x=0;
    char c=getchar();
    while(c>'9'||c<'0') c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x;
}

struct E
{
    int u,v,w,id,flag;
    
    void read()
    {
        u=get(); v=get(); w=get();
        if(u>v) swap(u,v);
        flag=1;
    }
};

E edge[N];

int cmp(E a,E b)
{
    if(a.u!=b.u) return a.u<b.u;
    return a.v<b.v;
}

int find(int u,int v)
{
    int low=1,high=m,mid;
    while(low<=high)
    {
        mid=(low+high)>>1;
        if(edge[mid].u==u&&edge[mid].v==v) return mid;
        if(edge[mid].u<u||edge[mid].u==u&&edge[mid].v<v) low=mid+1;
        else high=mid-1;
    }
}

void Add(int u,int v,int id)
{
    pair<int,int> p=query(u,v);
    if(p.first!=-1)   
    {
        if(p.second<=W[id]) return;
        cut(p.first,c[p.first][0]);
        cut(p.first,c[p.first][1]);
    }
    join(u,id);
    join(v,id);
}

int cmp1(E a,E b)
{
    return a.w<b.w;
}

int fa[N];

int get(int x)
{
    if(fa[x]!=x) fa[x]=get(fa[x]);
    return fa[x];
}

vector<int> g[N];
int visit[N];

void BFS(int u)
{
    queue<int> Q;
    Q.push(u);
    int i,v;
    while(!Q.empty())
    {
        u=Q.front();
        Q.pop();
        visit[u]=1;
        
        FOR0(i,SZ(g[u]))
        {
            v=g[u][i];
            if(a+v==a[u].f) continue;
            a[v].f=a+u;
            Q.push(v);
        }
    }
}

void build()
{
    sort(edge+1,edge+m+1,cmp1);
    int i,u,v,t;
    FOR1(i,n+m) fa[i]=i;
    FOR1(i,m) if(edge[i].flag)
    {
        u=get(edge[i].u);
        v=get(edge[i].v);
        if(u==v) continue;
        fa[u]=v;
        u=edge[i].u;
        v=edge[i].v;
        t=edge[i].id;
        g[u].pb(t); g[v].pb(t);
        g[t].pb(u); g[t].pb(v);
    }
    FOR1(i,n+m) if(!visit[i]) BFS(i);
    sort(edge+1,edge+m+1,cmp);
}

void go()
{
    int i;
    for(i=Q;i>=1;i--)
    {
        if(b[i].op==1) b[i].ans=query(b[i].u,b[i].v).second;
        else Add(b[i].u,b[i].v,edge[find(b[i].u,b[i].v)].id);
    }
    FOR1(i,Q) if(b[i].op==1) PR(b[i].ans);
}

int main()
{
    n=get(); m=get(); Q=get();
    init();
    int i,u,v,w,t;
    i64 x;
    FOR1(i,m)
    {
        edge[i].read();
        edge[i].id=i+n;
        c[i+n][0]=edge[i].u;
        c[i+n][1]=edge[i].v;
        W[n+i]=edge[i].w;
    }
    sort(edge+1,edge+m+1,cmp);
    FOR1(i,Q)
    {
        b[i].op=get(); 
        b[i].u=get(); 
        b[i].v=get();
        if(b[i].u>b[i].v) swap(b[i].u,b[i].v);
        if(b[i].op==2)
        {
            t=find(b[i].u,b[i].v);
            edge[t].flag=0;
        }
    }
    for(i=1;i<=n+m;i++)
    {
        a[i].c[0]=a[i].c[1]=a[i].f=nullNode;
        a[i].val=a[i].Max=W[i];
        a[i].maxNode=a[i].id=i;
        a[i].isRev=0;
    }
    build();
    go();
}

BZOJ 2594 水管局长数据加强版(动态树)的更多相关文章

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

    2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MBSubmit: 934  Solved: 291[Submit][Sta ...

  2. [BZOJ]2594 水管局长数据加强版(Wc2006)

    失踪人口回归. LCT一直是小C的弱项,特别是这种维护链的信息的,写挂了就会调代码调到心态爆炸. 不过还好这一次的模板练习没有出现太多的意外. Description SC省MY市有着庞大的地下水管网 ...

  3. bzoj 2594: 水管局长数据加强版 Link-Cut-Tree

    题目: Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公 ...

  4. BZOJ 2594 水管局长数据加强版

    LCT维护最小生成树 要求两点路径最大的最小,首先想到的肯定是最小生成树,再加上有删边操作,那就得用LCT维护了. 可是对于cut一条边,我们要时刻维护图中的最小生成树,需要把之前被我们淘汰的边找回, ...

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

    离线然后就是维护加边的动态MST, Link cut tree秒掉..不过我写+调了好久...时间复杂度O(NlogN + MlogM) ------------------------------- ...

  6. BZOJ 2594: [Wc2006]水管局长数据加强版 [LCT kruskal]

    2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec  Memory Limit: 128 MBSubmit: 2917  Solved: 918[Submit][St ...

  7. BZOJ 2594 【WC2006】 水管局长数据加强版

    题目链接:水管局长数据加强版 好久没写博客了…… 上次考试的时候写了一发LCT,但是写挂了……突然意识到我已经很久没有写过LCT了,于是今天找了道题来练练手. 首先,LCT这里不讲.这道题要求支持动态 ...

  8. BZOJ2594: [Wc2006]水管局长数据加强版

    题解: 裸LCT+离线+二分+MST... 代码:(几乎摘抄自hzwer) #include<cstdio> #include<cstdlib> #include<cma ...

  9. [bzoj2594][Wc2006]水管局长数据加强版 (lct)

    论蒟蒻的自我修养T_T.. 和noi2014魔法森林基本一样...然而数据范围大得sxbk...UPD:这题如果用lct判联通的话可能会被卡到O(mlogm)..所以最好还是用并查集吧 一开始数组开太 ...

随机推荐

  1. MongoDB的固态list

    在MongoDB中当前数据库所指定的list可以是一个固态的list,所谓固态就是大小确定,如创建一个固态的集合:db.createCollection("固态集合的名字",{ca ...

  2. mybatis中大于等于、小于等于的写法

    在xml格式中,常常会遇到xml解析sql时候出错,这个时候需要用其他符号来表示.在mybatis中会遇到,需要做如下的转换:

  3. json数据处理:读取文件中的json字符串,转为python字典

    方法1: 读取文件中的json字符串, 再用json.loads转为python字典 import json str_file = './960x540/config.json' with open( ...

  4. SQL Server中SCAN 和SEEK的区别

    SQL Server中SCAN 和SEEK的区别 SQL SERVER使用扫描(scan)和查找(seek)这两种算法从数据表和索引中读取数据.这两种算法构成了查询的基础,几乎无处不在.Scan会扫描 ...

  5. Sqoop导入HBase,并借助Coprocessor协处理器同步索引到ES

    1.环境 Mysql 5.6 Sqoop 1.4.6 Hadoop 2.5.2 HBase 0.98 Elasticsearch 2.3.5 2.安装(略过) 3.HBase Coprocessor实 ...

  6. 搭建基于HTTP协议内网yum仓库

    目录 1. 前言 2. 把rpm包下载到本地 3. 配置nginx对外提供服务 4. 配置本地repo文件 5. 生成repodata信息 6. 检查及使用 7. 对管理机器上的仓库进行更新 参考资料 ...

  7. 支持向量机:Numerical Optimization,SMO算法

    http://www.cnblogs.com/jerrylead/archive/2011/03/18/1988419.html 另外一篇:http://www.cnblogs.com/vivouni ...

  8. print(array)时array中间是省略号没有输出全部的解决方法

    import numpy as np np.set_printoptions(threshold=np.inf) 大量元素情况 可以采用set_printoptions(threshold='nan' ...

  9. qt mysql驱动问题解绝

    传统解决方法:一.解决问题 本文解决在Ubuntu16.04系统下,Qt5无法连接MySQL数据库的问题(Qt5缺少MySQL驱动,Qt5缺少libqsqlmysql.so动态库,如何安装libqsq ...

  10. ambari集成impala

    1.查看hdp版本,可在ambari-agent节点上查看 VERSION=`hdp-select status hadoop-client | sed 's/hadoop-client - \([0 ...