https://loj.ac/problem/10132

题目描述

  给出一棵\(N\)个点的树,有\(M\)个时刻,每个时刻有三种可能的事件:\(①\)某个点出现异象石;\(②\)某个点的异象石被摧毁;\(③\)求使异象石所在点被联通的边集的总长度。

思路

  题目给出的使一棵树,我们考虑对于这个树确定一个根后,求出它的\(dfs\)序。那么事实上对于已知的异象石,我们对它按照\(dfs\)序排成一圈之后,所求的就是相邻两个节点的距离之和的\(\frac{1}{2}\)(然而这个结论我也不会证,只能画图感性理解)。所以我们只要为维护这个序列,并能够快速求两点间距离。求距离我们可以用倍增,而维护序列的前驱后继我们可以用平衡树维护,注意处理一下只有一个点的细节即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+10;
const ll INF=1000000000;

ll nxt[N<<1],to[N<<1],tot,w[N<<1],head[N];
void add_edge(ll x,ll y,ll v)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
    w[tot]=v;
}

ll dfn[N],dep[N],f[N][22],dis[N],idx,p[N];
void dfs(ll u,ll fa,ll s)
{
    dis[u]=s;dfn[u]=++idx;p[idx]=u;
    dep[u]=dep[fa]+1;
    for(ll i=0;i<20;i++)
        f[u][i+1]=f[f[u][i]][i];
    for(ll i=head[u];i;i=nxt[i])
    {
        ll v=to[i];
        if(v==fa)continue ;
        f[v][0]=u;
        dfs(v,u,s+w[i]);
    }
}
ll LCA(ll x,ll y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(ll i=20;i>=0;i--)
    {
        if(dep[f[x][i]]>=dep[y])x=f[x][i];
        if(x==y)return y;
    }
    for(ll i=20;i>=0;i--)
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];
}
ll get_path(ll x,ll y)
{
//  cout<<x<<' '<<y<<endl;
    ll lca=LCA(x,y);
    return dis[x]+dis[y]-2*dis[lca];
}

struct Node
{
    ll lc,rc,w,v,cnt,siz;
}a[N];
ll root,sum,ss;
void upt(ll k)
{
    a[k].siz=a[a[k].lc].siz+a[a[k].rc].siz+a[k].cnt;
}
void zig(ll &k)
{
    ll t=a[k].lc;
    a[k].lc=a[t].rc;
    a[t].rc=k;
    a[t].siz=a[k].siz;
    upt(k);
    k=t;
}
void zag(ll &k)
{
    ll t=a[k].rc;
    a[k].rc=a[t].lc;
    a[t].lc=k;
    a[t].siz=a[k].siz;
    upt(k);
    k=t;
}
void insert(ll &k,ll key)
{
    if(!k)
    {
        k=++sum;
        a[k].siz=a[k].cnt=1;
        a[k].lc=a[k].rc=0;
        a[k].v=key;a[k].w=rand();
        return ;
    }
    else a[k].siz++;
    if(a[k].v==key)a[k].cnt++;
    else if(a[k].v<key)
    {
        insert(a[k].rc,key);
        if(a[a[k].rc].w<a[k].w)zag(k);
    }
    else
    {
        insert(a[k].lc,key);
        if(a[a[k].lc].w<a[k].w)zig(k);
    }
}
void f_delete(ll &k,ll key)
{
    if(a[k].v==key)
    {
        if(a[k].cnt>1)a[k].cnt--,a[k].siz--;
        else if(!a[k].lc||!a[k].rc)k=a[k].lc+a[k].rc;
        else if(a[a[k].lc].w<a[a[k].rc].w)zig(k),f_delete(k,key);
        else zag(k),f_delete(k,key);
        return ;
    }
    else a[k].siz--;
    if(a[k].v>key)
        f_delete(a[k].lc,key);
    else f_delete(a[k].rc,key);
}
ll findmin()
{
    ll x=root,res=INF;
    while(x)
    {
        res=min(res,a[x].v);
        x=a[x].lc;
    }
    return res;
}
ll findmax()
{
    ll x=root,res=-INF;
    while(x)
    {
        res=max(res,a[x].v);
        x=a[x].rc;
    }
    return res;
}
ll querypre(ll key)
{
    ll x=root,res=-INF;
    while(x)
    {
        if(a[x].v<key)res=max(res,a[x].v),x=a[x].rc;
        else x=a[x].lc;
    }
    if(res!=-INF)return res;
    else return findmax();
}
ll querynxt(ll key)
{
    ll x=root,res=INF;
    while(x)
    {
        if(a[x].v>key)res=min(res,a[x].v),x=a[x].lc;
        else x=a[x].rc;
    }
    if(res!=INF)return res;
    else return findmin();
}

ll read()
{
    ll res=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    return res*w;
}
void write(ll x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
void writeln(ll x)
{
    write(x);
    putchar('\n');
}

int main()
{
    ll n,m;
    n=read();
    for(ll i=1;i<n;i++)
    {
        ll x=read(),y=read(),z=read();
        add_edge(x,y,z);add_edge(y,x,z);
    }
    dfs(1,0,0);
    m=read();
    ll ans=0;
//  for(int i=1;i<=n;i++)
//      printf("%d ",dfn[i]);
//  printf("\n");
    while(m--)
    {
        char op;
        scanf(" %c",&op);
        if(op=='+')
        {
            ll x=read();ss++;
            if(ss<=1){insert(root,dfn[x]);ans=0;continue ;}
            ll l=querypre(dfn[x]),r=querynxt(dfn[x]);
//          cout<<l<<' '<<r<<endl;
            l=p[l];r=p[r];
            insert(root,dfn[x]);
            ans=ans+get_path(l,x)+get_path(x,r)-get_path(l,r);
        }
        else if(op=='-')
        {
            ll x=read();ss--;
            if(ss<=1){f_delete(root,dfn[x]);ans=0;continue ;}
            ll l=querypre(dfn[x]),r=querynxt(dfn[x]);
//          cout<<l<<' '<<r<<endl;
            l=p[l];r=p[r];
            f_delete(root,dfn[x]);
            ans=ans-get_path(l,x)-get_path(x,r)+get_path(l,r);
        }
        else
            writeln(ans/2);
//      cout<<ans<<endl;
    }
    return 0;
}
01-10 18:30