[2016北京集训试题14]股神小D-[LCT]

Description

Solution

将(u,v,l,r)换为(1,u,v,l)和(2,u,v,r)。进行排序(第4个数为第一关键字,第1个数为第二关键字)。用LCT维护联通块的合并和断开。(维护联通块的大小,要维护虚边)

答案统计:每当四元组的第一个数为1(这时候合并点u,v所在连通块,反之拆开),在合并前ans+=size[u]*size[v]即可。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e5+10;
long long ans;
struct LCT
{
    int val[N],sz[N],v[N],fa[N],ch[N][2],rev[N];
    bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    bool get(int x){return ch[fa[x]][1]==x;}
    void updata(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+v[x]+1;}
    void rotate(int x)
    {
        int k=get(x),y=fa[x];
        ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
        if (!isroot(y)) ch[fa[y]][ch[fa[y]][1]==y]=x;fa[x]=fa[y];
        fa[y]=x;ch[x][k^1]=y;
        updata(y);
        updata(x);  
    }
    void pushdown(int x)
    {
        if (rev[x])
        {
            swap(ch[x][0],ch[x][1]);
            rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;
            rev[x]=0;
        }
    }
    int q[N],cnt;
    void splay(int x)
    {
        int y;
        q[cnt=1]=x;
        for (int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];
        for (int i=cnt;i>=1;i--) pushdown(q[i]),fa[q[i]]=fa[q[i]];
        while (!isroot(x))
        {
            y=fa[x];
            if (!isroot(y)) rotate(get(x)==get(y)?y:x);
            rotate(x);
        }
    }
    void access(int x)
    {
        int y=0;
        while (x)
        {
            splay(x);
            v[x]+=sz[ch[x][1]]-sz[y];
            ch[x][1]=y;
            updata(x);
            y=x;x=fa[x];
        }
    }
    void mroot(int x)
    {
        access(x);splay(x);rev[x]^=1;
    }
    void link(int x,int y)
    {
        mroot(x);access(y);splay(y);
        ans+=1ll*sz[x]*sz[y];
        fa[x]=y;v[y]+=sz[x];updata(y);
    }
    void cut(int x,int y)
    {
        mroot(x);access(y);splay(y);
        fa[x]=ch[y][0]=0;
        updata(y);
    }
}lct;
int n,u,v,l,r;
struct Q{int t,u,v,w;
    friend bool operator <(Q a,Q b){return a.w==b.w?a.t<b.t:a.w<b.w;}
}q[N<<1];
int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d%d%d",&u,&v,&l,&r);
        q[i*2-1]=Q{1,u,v,l};q[i*2]=Q{2,u,v,r};
    }
    sort(q+1,q+2*n-1);
    for (int i=1;i<=2*n-2;i++)
    {
        if (q[i].t==1) lct.link(q[i].u,q[i].v);
        else lct.cut(q[i].u,q[i].v);
    }
    cout<<ans;
}

猜你喜欢

转载自www.cnblogs.com/coco-night/p/9696166.html