题目链接: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. LCA——最近公共祖先

    今天终于把倍增的LCA搞懂了!尽管周测都没写,尽管lca其实很简单,但这也是进度君的往前一点点的快乐.学渣的呻吟. 倍增的lca其实关键就在于二进制的二进制的拆分(显然是两次的拆分,很奇妙,懂二进制的 ...

  2. Nginx日志切割之Logrotate篇

    不管是什么日志文件,都是会越来越大的,大到一定程度就是个可怕的事情了,所以要及早的做处理,方法之一就是按时间段来存储,不过linux系统提供了Logrotate的日志管理工具,很好用,不用写计划任务脚 ...

  3. 迷宫问题---poj3984(bfs,输出路径问题)

    题目链接 主要就是输出路径问题: pre[x][y]表示到达(x,y)是由点(pre[x][y].x,  pre[x][y].y)而来: #include<stdio.h> #includ ...

  4. 面向切面编程--AOP(转)

    add by zhj:面向切面编程就是在不修改函数A的前提下,在函数A前后插入业务逻辑B, C, D...这其实算是功能分解,将大模块S=A+B+C+D+……分解为独立的小功能A,B,C,D……,模块 ...

  5. .NET数据挖掘与机器学习开源框架

    1.    数据挖掘与机器学习开源框架 1.1 框架概述 1.1.1 AForge.NET AForge.NET是一个专门为开发者和研究者基于C#框架设计的,他包括计算机视觉与人工智能,图像处理,神经 ...

  6. Celery框架简单实例

    Python 中可以使用Celery框架 Celery框架是提供异步任务处理的框架,有两种用法,一种:应用程式发布任务消息,后台Worker监听执行,好处在于不影响应用程序继续执行.第二种,设置定时执 ...

  7. host文件常用地址

    #+UPDATE_TIME 2016-02-16 19:52:05 UTC+8#+MESSAGE#################################################### ...

  8. Mac SVN版本从1.9降到1.8

    假设系统已安装brew,在终端执行下列命令: brew update brew install subversion18 echo 'export PATH="/usr/local/opt/ ...

  9. application实例

    application详解及实例 application对象用来在多个程序或者是多个用户之间共享数据,用户使用的所有application对象都是一样的,这与session对象不同.服务器一旦启动,就 ...

  10. PAT 1076 Forwards on Weibo[BFS][一般]

    1076 Forwards on Weibo (30)(30 分) Weibo is known as the Chinese version of Twitter. One user on Weib ...