首页 > 技术文章 > Luogu4115 Qtree4

GK0328 2020-11-01 17:52 原文

https://www.luogu.com.cn/problem/P4115

这道题明显是动态点分治板子,但是用树剖写起来就显得十分困难了。

由于本题维护的是全局信息,我们不能仅从线段树上直接读取答案。

不过树链剖分维护的就是链信息,因此我们考虑如果是链应该怎么做。

求一段区间中的最远白点距离,这很容易维护,只需要求出这个区间离左端、右端的最近白点,同时记录整个区间的答案,就可以轻松合并。

我们把所有的重子树都用线段树维护,轻子树用\(multiset\)储存答案,那么我们修改时只需要沿着重链跳到根,每到轻重儿子交换的时候就修改\(multiset\)内的值,同时单点修改线段树中的值,这样的维护方式与动态dp有异曲同工之妙。

全局答案可以再开一个\(multiset\),同时修改。

这里线段树维护的值看起来十分奇怪,如果随便抽取一个区间求值,它可能是没有意义的,但是我们每次取一条重链的值,由于\(dfn\)序连续,读取的值必然是有意义的。

总时间复杂度:\(O(n \log^2 n)\)

\(n \log n\)的神仙做法暂时咕着吧。。。

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#define N 100005
#define INF 1000000007
using namespace std;
int n,x,y,z,ct;
struct node
{
    int nxt,v,cost;
    node (int xx=0,int yy=0,int zz=0)
    {
        nxt=xx,v=yy,cost=zz;
    }
}e[N << 1];
int tot,q,f[N],fr[N];
int sz[N],son[N],val[N],d[N];
int cnt,dfn[N],rdfn[N],t[N],dis[N];
int lst[N][2];
bool col[N];
char opt[5];
struct cmp
{
    bool operator () (int x,int y)
    {
        return x>y;
    } 
};
multiset<int,cmp>s[N],ans;
void add(int x,int y,int z)
{
    ++tot;
    e[tot]=node(fr[x],y,z),fr[x]=tot;
}
void dfs1(int u)
{
    int mx=-1;
    sz[u]=1;
    for (int i=fr[u];i;i=e[i].nxt)
    {
        int v=e[i].v,cost=e[i].cost;
        if (v==f[u])
            continue;
        dis[v]=dis[u]+cost;
        val[v]=cost;
        f[v]=u;
        dfs1(v);
        sz[u]+=sz[v];
        if (sz[v]>mx)
            mx=sz[v],son[u]=v;
    }
}
void dfs2(int u,int tp)
{
    dfn[u]=++cnt;
    rdfn[cnt]=u;
    t[u]=tp;
    if (!son[u])
    {
        d[tp]=u;
        return;
    }
    dfs2(son[u],tp);
    for (int i=fr[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (v==f[u] || v==son[u])
            continue;
        dfs2(v,v);
    }
}
struct Mxdis
{
    int l,r,v;
    Mxdis (int L=0,int R=0,int V=0)
    {
        l=L,r=R,v=V;
    }
}tr[N << 2];
Mxdis Merge(Mxdis a,Mxdis b,int L,int DL,int DR)
{
    Mxdis c;
    c.v=max(max(a.v,b.v),a.r+L+b.l);
    c.l=max(a.l,DL+L+b.l);
    c.r=max(b.r,DR+L+a.r);
    return c;
}
int id(int x)
{
    return rdfn[x];
}
void build(int p,int l,int r)
{
    if (l==r)
        return;
    int mid=(l+r) >> 1;
    build(p << 1,l,mid);
    build(p << 1 | 1,mid+1,r);
    tr[p]=Merge(tr[p << 1],tr[p << 1 | 1],val[id(mid+1)],dis[id(mid)]-dis[id(l)],dis[id(r)]-dis[id(mid+1)]);
}
void modify(int p,int l,int r,int x)
{
    if (l==r)
    {
        int mx=-INF,se=-INF,tx=id(x);
        if (!col[tx])
            mx=se=0;
        if (!s[tx].empty())
            mx=max(mx,*s[tx].begin());
        if (s[tx].size()>1)
            se=max(se,*(++s[tx].begin()));
        tr[p].l=tr[p].r=mx;
        if (!col[tx])
            tr[p].v=max(mx,mx+se); else
            tr[p].v=max(-INF,mx+se);
        return;
    }
    int mid=(l+r) >> 1;
    if (x<=mid)
        modify(p << 1,l,mid,x); else
        modify(p << 1 | 1,mid+1,r,x);
    tr[p]=Merge(tr[p << 1],tr[p << 1 | 1],val[id(mid+1)],dis[id(mid)]-dis[id(l)],dis[id(r)]-dis[id(mid+1)]);
}
Mxdis calc(int p,int l,int r,int x,int y)
{
    if (l==x && r==y)
        return tr[p];
    int mid=(l+r) >> 1;
    if (y<=mid)
        return calc(p << 1,l,mid,x,y); else
    if (x>mid)
        return calc(p << 1 | 1,mid+1,r,x,y); else
        return Merge(calc(p << 1,l,mid,x,mid),calc(p << 1 | 1,mid+1,r,mid+1,y),
        val[id(mid+1)],dis[id(mid)]-dis[id(x)],dis[id(y)]-dis[id(mid+1)]);
}
int dfs3(int u)
{
    for (int i=u;i;i=son[i])
    {
        for (int j=fr[i];j;j=e[j].nxt)
        {
            int v=e[j].v;
            if (v==f[i] || v==son[i])
                continue;
            int k=dfs3(v);
            s[i].insert(k+e[j].cost);
        }
        modify(1,1,n,dfn[i]);
    }
    Mxdis k=calc(1,1,n,dfn[u],dfn[d[u]]);
    lst[u][0]=k.l,lst[u][1]=k.v;
    ans.insert(k.v);
    return k.l;
}
Mxdis calc2(int u)
{
    return calc(1,1,n,dfn[u],dfn[d[u]]);
}
void change(int x)
{
    Mxdis z;
    for (;;)
    {
        modify(1,1,n,dfn[x]);
        z=calc2(t[x]);
        ans.erase(ans.find(lst[t[x]][1]));
        ans.insert(z.v);
        lst[t[x]][1]=z.v;
        if (!f[t[x]])
        {
            lst[t[x]][0]=z.l;
            return;
        }
        int tt=f[t[x]];
        s[tt].erase(s[tt].find(lst[t[x]][0]+val[t[x]]));
        s[tt].insert(z.l+val[t[x]]);
        lst[t[x]][0]=z.l;
        x=f[t[x]];
    }
}
int main()
{
    scanf("%d",&n),ct=n;
    for (int i=1;i<n;++i)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z),add(y,x,z);
    }
    dfs1(1);
    dfs2(1,1);
    build(1,1,n);
    dfs3(1);
    scanf("%d",&q);
    while (q--)
    {
        scanf("%s",opt);
        if (opt[0]=='A')
        {
            if (!ct)
                puts("They have disappeared."); else
            if (ct==1)
                puts("0"); else
                printf("%d\n",*ans.begin());
        } else
        {
            scanf("%d",&x);
            if (col[x])
                ++ct; else
                --ct;
            col[x]=!col[x];
            change(x);
        }
    }
    return 0;
}

推荐阅读