zoukankan      html  css  js  c++  java
  • [清华集训2016]温暖会指引我们前行——LCT+最大生成树

    题目链接:

    [清华集训2016]温暖会指引我们前行

    题目大意:有$n$个点$m$次操作,每次操作分为三种:1、在$u,v$两点之间连接一条编号为$id$,长度为$l$,温度为$t$的边。2、查询从$u$到$v$的最温暖的路径长度(定义最温暖的路径为将路径上的边按温度从小到大排序后字典序尽可能大)。3、将编号为$id$的边长度修改为$l$。

    仔细读题发现题目中说的字典序其实就是使路径上的边都尽可能大。

    那么最优方案一定就是走最大生成树上的边咯。

    用LCT动态维护最大生成树。

    当新加入边两端点不连通时直接连接,否则找到两点路径上的最小边,如果当前边比最小边大,那么将最小边删除并加入当前边。

    在LCT上维护边的信息不好做,我们将每个边看成一个点。

    例如编号为a的边连接x,y,那么就将a+n这个新建点分别连向x,y。

    splay需要维护最小点权,点权和及最小点权点编号。

    注意要将所有非边点的点权置成INF。

    注意在find之后要将原树根旋到它所在splay的根,否则在uoj会被卡。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<bitset>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define pr pair<int,int>
    #define ll long long
    using namespace std;
    char ch[10];
    int n,m;
    int x,y,z,u,v;
    struct miku
    {
        int x,y;
    }a[600010];
    int s[800010][2];
    int mx[800010];
    int mn[800010];
    int r[800010];
    int f[800010];
    int w[800010];
    int st[800010];
    int sum[800010];
    int t[800010];
    int is_root(int rt)
    {
        return rt!=s[f[rt]][0]&&rt!=s[f[rt]][1];
    }
    int get(int rt)
    {
        return rt==s[f[rt]][1];
    }
    void pushup(int rt)
    {
        sum[rt]=sum[s[rt][0]]+sum[s[rt][1]]+w[rt];
        mx[rt]=min(t[rt],min(mx[s[rt][0]],mx[s[rt][1]]));
        if(mx[rt]==t[rt])
        {
            mn[rt]=rt;
        }
        else if(mx[rt]==mx[s[rt][0]])
        {
            mn[rt]=mn[s[rt][0]];
        }
        else
        {
            mn[rt]=mn[s[rt][1]];
        }
    }
    void pushdown(int rt)
    {
        if(r[rt])
        {
            swap(s[rt][0],s[rt][1]);
            r[s[rt][0]]^=1;
            r[s[rt][1]]^=1;
            r[rt]^=1;
        }
    }
    void rotate(int rt)
    {
        int fa=f[rt];
        int anc=f[fa];
        int k=get(rt);
        if(!is_root(fa))
        {
            s[anc][get(fa)]=rt;
        }
        s[fa][k]=s[rt][k^1];
        f[s[fa][k]]=fa;
        s[rt][k^1]=fa;
        f[fa]=rt;
        f[rt]=anc;
        pushup(fa);
        pushup(rt);
    }
    void splay(int rt)
    {
        int top=0;
        st[++top]=rt;
        for(int i=rt;!is_root(i);i=f[i])
        {
            st[++top]=f[i];
        }
        for(int i=top;i>=1;i--)
        {
            pushdown(st[i]);
        }
        for(int fa;!is_root(rt);rotate(rt))
        {
            if(!is_root(fa=f[rt]))
            {
                rotate(get(fa)==get(rt)?fa:rt);
            }
        }
    }
    void access(int rt)
    {
        for(int x=0;rt;x=rt,rt=f[rt])
        {
            splay(rt);
            s[rt][1]=x;
            pushup(rt);
        }
    }
    void reverse(int rt)
    {
        access(rt);
        splay(rt);
        r[rt]^=1;
    }
    int find(int rt)
    {
        access(rt);
        splay(rt);
        while(s[rt][0])
        {
            rt=s[rt][0];
        }
        splay(rt);
        return rt;
    }
    void link(int x,int y)
    {
        reverse(x);
        f[x]=y;
    }
    void cut(int x,int y)
    {
        reverse(x);
        access(y);
        splay(y);
        if(s[x][1]||f[x]!=y)
        {
            return ;
        }
        f[x]=s[y][0]=0;
        pushup(y);
    }
    void change(int rt,int x)
    {
        w[rt]=x;
        access(rt);
        splay(rt);
    }
    int query(int x,int y)
    {
        reverse(x);
        access(y);
        splay(y);
        return mn[y];
    }
    int ask(int x,int y)
    {
        reverse(x);
        access(y);
        splay(y);
        return sum[y];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++)
        {
            t[i]=1000000007;
            mx[i]=1000000007;
            mn[i]=i;
            w[i]=0;
            sum[i]=0;
        }
        while(m--)
        {
            scanf("%s",ch);
            if(ch[0]=='f')
            {
                scanf("%d%d%d%d%d",&x,&u,&v,&y,&z);
                u++;
                v++;
                x++;
                a[x].x=u;
                a[x].y=v;
                t[n+x]=y;
                w[n+x]=z;
                sum[n+x]=z;
                mn[n+x]=n+x;
                if(find(u)==find(v))
                {
                    int id=query(u,v);
                    if(y>mx[id])
                    {
                        cut(id,a[id-n].x);
                        cut(id,a[id-n].y);
                        link(n+x,u);
                        link(n+x,v);
                    }
                }
                else
                {
                    link(n+x,u);
                    link(n+x,v);
                }
            }
            else if(ch[0]=='c')
            {
                scanf("%d%d",&x,&y);
                x++;
                change(n+x,y);
            }
            else
            {
                scanf("%d%d",&u,&v);
                u++;
                v++;
                if(find(u)==find(v))
                {
                    printf("%d
    ",ask(u,v));
                }
                else
                {
                    printf("-1
    ");
                }
            }
        }
    }
  • 相关阅读:
    层次遍历二叉树时的一个技巧
    合并两个有序链表
    关于指针的引用和“||”运算符的一些心得
    UE4中显示AI Debug信息
    EQS 自定义Context 如何用Testing Pawn 进行测试?
    4.16中Montage的一些变化
    Move Controller UE4键位
    EQS
    获取文件完整路径快捷方法
    同步引擎版本号的简易方法
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9954626.html
Copyright © 2011-2022 走看看