zoukankan      html  css  js  c++  java
  • [BZOJ]2594 水管局长数据加强版(Wc2006)

      失踪人口回归。

      LCT一直是小C的弱项,特别是这种维护链的信息的,写挂了就会调代码调到心态爆炸。

      不过还好这一次的模板练习没有出现太多的意外。

    Description

      SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了。嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项。
      在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗、消毒等等。嘟嘟在控制中心一声令下,这些水管的准备操作同时开始,但由于各条管道的长度、内径不同,进行准备操作需要的时间可能不同。供水公司总是希望嘟嘟能找到这样一条送水路径,路径上的所有管道全都准备就绪所需要的时间尽量短。嘟嘟希望你能帮助他完成这样的一个选择路径的系统,以满足供水公司的要求。另外,由于MY市的水管年代久远,一些水管会不时出现故障导致不能使用,你的程序必须考虑到这一点。
      不妨将MY市的水管网络看作一幅简单无向图(即没有自环或重边):水管是图中的边,水管的连接处为图中的结点。

    Input

      输入文件第一行为3个整数:N, M, Q分别表示管道连接处(结点)的数目、目前水管(无向边)的数目,以及你的程序需要处理的任务数目(包括寻找一条满足要求的路径和接受某条水管坏掉的事实)。
    以下M行,每行3个整数x, y和t,描述一条对应的水管。x和y表示水管两端结点的编号,t表示准备送水所需要的时间。我们不妨为结点从1至N编号,这样所有的x和y都在范围[1, N]内。
      以下Q行,每行描述一项任务。其中第一个整数为k:若k=1则后跟两个整数A和B,表示你需要为供水公司寻找一条满足要求的从A到B的水管路径;若k=2,则后跟两个整数x和y,表示直接连接x和y的水管宣布报废(保证合法,即在此之前直接连接x和y尚未报废的水管一定存在)。

    Output

      按顺序对应输入文件中每一项k=1的任务,你需要输出一个数字和一个回车/换行符。该数字表示:你寻找到的水管路径中所有管道全都完成准备工作所需要的时间(当然要求最短)。

    Sample Input

      4 4 3
      1 2 2
      2 3 3
      3 4 2
      1 4 2
      1 1 4
      2 1 4
      1 1 4

    Sample Output

      2
      3

    HINT

      N ≤ 100000
      M ≤ 1000000
      Q ≤ 100000
      任何时候我们考虑的水管网络都是连通的,即从任一结点A必有至少一条水管路径通往任一结点B。

    Solution

      很容易看出题目要求我们维护无向图的最小生成树,查询两点树上路径最大权值,并支持删边操作。

      删边不好处理,而且题目没有要求我们在线,我们很容易想到倒过来做,把删边改为加边。

      于是用hash判断删去了哪些边(注意hash可能会撞),对删去所有边之后的图做最小生成树。

      这样就是LCT维护最小生成树的裸题了。

      对于每条新加入的边,查找两端点之间路径最大权值,如果小于那个权值,就删去那条边,并加入这条边。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define l(a) son[a][0]
    #define r(a) son[a][1]
    #define nrt(a) (l(fa[a])==a || r(fa[a])==a)
    #define MM 1000005
    #define MN 100005
    #define mod 10000007
    using namespace std;
    struct meg1{int x,y,z;}a[MM];
    struct meg2{int g,x,y,z,pos;}b[MN];
    struct edge{int nex,to,wt,pos;}e[MN<<1];
    struct dmp{dmp *nex; int x,y,val;}*mp[mod];
    int son[MN][2],fa[MN],tfa[MN],tson[MN],tg[MN],mx[MN];
    int hr[MN],hua[MN],pin;
    int n,m,p;
    
    inline int read()
    {
        int n=0,f=1; char c=getchar();
        while (c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
        while (c>='0' && c<='9') {n=n*10+c-'0'; c=getchar();}
        return n*f;
    }
    
    void revs(int x) {tg[x]^=1; swap(l(x),r(x)); swap(tfa[x],tson[x]);}
    void down(int x) {if (tg[x]) {revs(l(x)); revs(r(x)); tg[x]=0;}}
    int L(int x) {down(x); return l(x)?L(l(x)):x;}
    void aldown(int x) {if (nrt(x)) aldown(fa[x]); down(x);}
    void upd(int &x,int y) {if (a[y].z>a[x].z) x=y;}
    void update(int x) {mx[x]=0; upd(mx[x],tfa[x]); upd(mx[x],tson[x]); upd(mx[x],mx[l(x)]); upd(mx[x],mx[r(x)]);}
    void rotate(int x)
    {
        register int y,z,l,r;
        y=fa[x]; z=fa[y]; l=r(y)==x; r=l^1;
        if (nrt(y)) son[z][r(z)==y]=x;
        fa[y]=x; fa[x]=z; fa[son[x][r]]=y;
        son[y][l]=son[x][r]; son[x][r]=y;
        update(y);
    }
    void splay(int x)
    {
        aldown(x);
        register int y,z;
        for (;nrt(x);rotate(x))
            {y=fa[x]; if (nrt(y)) z=fa[y],rotate(r(z)==y^r(y)==x?x:y);}
        update(x);
    }
    void access(int x)
    {
        for (int i=0;x;x=fa[i=x])
        {
            splay(x); tson[x]=tfa[L(i)];
            r(x)=i; update(x);
        }
    }
    
    int getmx(int x,int y)
    {
        access(x); splay(x); revs(x);
        access(y); splay(y); return mx[y];
    }
    void link(int x,int y,int z)
    {
        access(x); splay(x);
        access(y); splay(y); revs(y);
        fa[y]=x; r(x)=y; tfa[y]=tson[x]=z;
        update(y); update(x);
    }
    void cut(int x,int y)
    {
        access(x); splay(x); revs(x);
        access(y); splay(y);
        l(y)=fa[l(y)]=0; tson[x]=tfa[y]=0;
        update(x); update(y);
    }
    
    inline void ins(int x,int y,int z,int w)
    {
        e[++pin]=(edge){hr[x],y,z,w}; hr[x]=pin;
        e[++pin]=(edge){hr[y],x,z,w}; hr[y]=pin;
    }
    void dfs(int x,int fat)
    {
        fa[x]=fat;
        for (register int i=hr[x];i;i=e[i].nex)
            if (e[i].to!=fat) mx[e[i].to]=tfa[e[i].to]=e[i].pos,dfs(e[i].to,x);
    }
    inline bool gather(int x,int y)
    {
        if (x==y) return false;
        hua[x]=y; return true;
    }
    int getf(int x) {return hua[x]?hua[x]=getf(hua[x]):x;}
    bool cmp(const meg1& a,const meg1& b) {return a.z<b.z;}
    
    int seamp(int h,int x,int y)
    {
        for (dmp* q=mp[h];q;q=q->nex) if (q->x==x && q->y==y) return q->val;
        return 0;
    }
    void insmp(int h,int x,int y,int z)
    {
        dmp* q=new(dmp);
        q->nex=mp[h]; q->x=x; q->y=y; q->val=z; mp[h]=q;
    }
    int geth(int x,int y) {return (1LL*x*300007+y)%mod;}
    
    int main()
    {
        register int i,lt;
        n=read(); m=read(); p=read();
        for (i=1;i<=m;++i)
        {
            a[i].x=read(); a[i].y=read(); a[i].z=read();
            if (a[i].x>a[i].y) swap(a[i].x,a[i].y);
        }
        for (i=1;i<=p;++i)
        {
            b[i].g=read(); b[i].x=read(); b[i].y=read();
            if (b[i].x>b[i].y) swap(b[i].x,b[i].y);
            if (b[i].g==2) insmp(geth(b[i].x,b[i].y),b[i].x,b[i].y,i);
        }
        sort(a+1,a+m+1,cmp);
        for (i=1;i<=m;++i)
        {
            if (lt=seamp(geth(a[i].x,a[i].y),a[i].x,a[i].y)) {b[lt].pos=i; continue;}
            if (gather(getf(a[i].x),getf(a[i].y))) ins(a[i].x,a[i].y,a[i].z,i);
        }
        dfs(1,0);
        for (i=p;i;--i)
        {
            if (b[i].g==1) b[i].z=a[getmx(b[i].x,b[i].y)].z;
            else if (b[i].g==2) {if (a[b[i].pos].z<a[lt=getmx(b[i].x,b[i].y)].z) cut(a[lt].x,a[lt].y),link(b[i].x,b[i].y,b[i].pos);}
        }
        for (i=1;i<=p;++i) if (b[i].g==1) printf("%d
    ",b[i].z);
    }

    Last Word

      由于link和cut部分可能有点难以理解,LCT一直是令小C头疼的算法之一,但是小C还是成功把模板默出来了。

      然后迷之RE,并且发现树上部分节点的关系违背了伦理道德。调完hash之后,结果发现是在找最左边的节点的节点时忘记down操作了。

      果然LCT在维护信息时,考虑哪里需要update,哪里需要down,顺序是什么是最烦的。

      不得不说,D-map真的好用。

  • 相关阅读:
    ssh 使用密钥文件
    VS2015企业版,社区版,专业版详细对比
    Redis 与 数据库处理数据的两种模式(转)
    工业级物联网项目架构设计思想(转)
    C# and Redis,安装作为服务
    C# CRC32
    c++,C# 转换
    app配置智能硬件的解决方案
    C# 与C++的数据转换
    C++ 对数组sizeof 和对数组元素sizeof
  • 原文地址:https://www.cnblogs.com/ACMLCZH/p/7099299.html
Copyright © 2011-2022 走看看