BZOJ3159 决战

题意


分析

树剖套平衡树。

难点在于路径翻转,其他的线段树都可以解决。

考虑套Splay,随便想想这操作就是将\(O(\log n)\)的区间翻转,翻转一个耗时\(O(\log n)\),所以总复杂度是\(O(\log^2 n)\)的。

然而你仔细想想貌似没有那么简单,主要是代码很烦,这么那么对应的。

注意到这题的性质,X国司令的操作的起点和终点的选取,都十分的睿智,这为我们简化代码提供了条件。若以r为根来树剖,那么这些区间端点的dfn是有序的,因为祖先的dfn小于后代的dfn。

然后就可以方便的将带翻转的区间提取出来,合并成一棵树,翻转一下,再拆分回去,最后合并起来即为新树。

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

打代码的时候我努力追求码风,然后每个细节都考虑的非常清楚,交上去竟然一遍AC了。自我感觉良好。

代码

我用函数式Treap实现了Splay。(话说Splay现在除了在LCT里面有用之外就是个废物)

我没有卡常,我也不喜欢卡常。

扫描二维码关注公众号,回复: 5013487 查看本文章
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
    rg T data=0;
    rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data*w;
}
template<class T>il T read(rg T&x)
{
    return x=read<T>();
}
typedef long long ll;

co int N=5e4+7;

int root,tot;
namespace T
{
    int ch[N][2],siz[N],pri[N];
    ll val[N],sum[N],max[N],min[N],tag[N];
    bool rev[N];
    
    int newnode(ll v)
    {
        int x=++tot;
        ch[x][0]=ch[x][1]=0,siz[x]=1,pri[x]=rand();
        val[x]=sum[x]=v;
        max[x]=min[x]=v;
        tag[x]=rev[x]=0;
        return x;
    }
    
    void pushup(int x)
    {
        siz[x]=siz[ch[x][0]]+1+siz[ch[x][1]];
        sum[x]=sum[ch[x][0]]+val[x]+sum[ch[x][1]];
        max[x]=std::max(max[ch[x][0]],std::max(val[x],max[ch[x][1]]));
        min[x]=std::min(min[ch[x][0]],std::min(val[x],min[ch[x][1]]));
    }
    
    void rever(int x)
    {
        std::swap(ch[x][0],ch[x][1]);
        rev[x]^=1;
    }
    
    void add(int x,ll v)
    {
        val[x]+=v;
        sum[x]+=siz[x]*v;
        max[x]+=v;
        min[x]+=v;
        tag[x]+=v;
    }
    
    void pushdown(int x)
    {
        if(rev[x])
        {
            if(ch[x][0])
                rever(ch[x][0]);
            if(ch[x][1])
                rever(ch[x][1]);
            rev[x]=0;
        }
        if(tag[x])
        {
            if(ch[x][0])
                add(ch[x][0],tag[x]);
            if(ch[x][1])
                add(ch[x][1],tag[x]);
            tag[x]=0;
        }
    }
    
    void split(int x,int k,int&l,int&r)
    {
        if(!x)
        {
            l=r=0;
            return;
        }
        if(siz[ch[x][0]]+1<=k)
        {
            l=x;
            pushdown(l);
            split(ch[l][1],k-siz[ch[x][0]]-1,ch[l][1],r);
            pushup(l);
        }
        else
        {
            r=x;
            pushdown(r);
            split(ch[r][0],k,l,ch[r][0]);
            pushup(r);
        }
    }
    
    int merge(int x,int y)
    {
        if(!x||!y)
            return x+y;
        if(pri[x]>pri[y])
        {
            pushdown(x);
            ch[x][1]=merge(ch[x][1],y);
            pushup(x);
            return x;
        }
        else
        {
            pushdown(y);
            ch[y][0]=merge(x,ch[y][0]);
            pushup(y);
            return y;
        }
    }
    
    void Increase(int&t,int l,int r,ll v)
    {
        int x,y,z;
        split(t,l-1,x,y);
        split(y,r-l+1,y,z);
        if(y)
            add(y,v);
        t=merge(x,merge(y,z));
    }
    
    ll Sum(int&t,int l,int r)
    {
        int x,y,z;
        split(t,l-1,x,y);
        split(y,r-l+1,y,z);
        ll res=sum[y];
        t=merge(x,merge(y,z));
        return res;
    }
    
    ll Major(int&t,int l,int r)
    {
        int x,y,z;
        split(t,l-1,x,y);
        split(y,r-l+1,y,z);
        ll res=max[y];
        t=merge(x,merge(y,z));
        return res;
    }
    
    ll Minor(int&t,int l,int r)
    {
        int x,y,z;
        split(t,l-1,x,y);
        split(y,r-l+1,y,z);
        ll res=min[y];
        t=merge(x,merge(y,z));
        return res;
    }
    
    typedef std::pair<int,int> pii;
    typedef std::vector<pii> path;
    typedef std::vector<int> subtree;
    
    void Invert(int&t,path p)
    {
        subtree s;
        s.push_back(t);
        for(int i=p.size()-1;i>=0;--i)
        {
            int x=s.back(),l,r;
            s.pop_back();
            split(x,p[i].second,x,r);
            split(x,p[i].first-1,l,x);
            s.push_back(r);
            s.push_back(x);
            s.push_back(l);
        }
        reverse(s.begin(),s.end());
        for(int i=1;i<p.size();++i)
            s[1]=merge(s[1],s[2*i+1]);
        rever(s[1]);
        for(int i=p.size()-1;i;--i)
            split(s[1],siz[s[1]]-(p[i].second-p[i].first+1),s[1],s[2*i+1]);
        for(int i=1;i<s.size();++i)
            s[0]=merge(s[0],s[i]);
        t=s[0];
    }
}

int n,m,r;
std::vector<int>g[N];
int dep[N],siz[N],fa[N],son[N];

void dfs1(int x,int fa)
{
    dep[x]=dep[fa]+1,siz[x]=1,::fa[x]=fa;
    for(int i=0;i<g[x].size();++i)
    {
        int y=g[x][i];
        if(y==fa)
            continue;
        dfs1(y,x);
        siz[x]+=siz[y];
        if(siz[y]>siz[son[x]])
            son[x]=y;
    }
}
    
int dfn[N],id,top[N];

void dfs2(int x,int top)
{
    dfn[x]=++id,::top[x]=top;
    if(!son[x])
        return;
    dfs2(son[x],top);
    for(int i=0;i<g[x].size();++i)
    {
        int y=g[x][i];
        if(y==fa[x]||y==son[x])
            continue;
        dfs2(y,y);
    }
}

void Increase(int x,int y,ll v)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            std::swap(x,y);
        T::Increase(root,dfn[top[x]],dfn[x],v);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        std::swap(x,y);
    T::Increase(root,dfn[x],dfn[y],v);
}

ll Sum(int x,int y)
{
    ll res=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            std::swap(x,y);
        res+=T::Sum(root,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        std::swap(x,y);
    res+=T::Sum(root,dfn[x],dfn[y]);
    return res;
}

ll Major(int x,int y)
{
    ll res=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            std::swap(x,y);
        res=std::max(res,T::Major(root,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        std::swap(x,y);
    res=std::max(res,T::Major(root,dfn[x],dfn[y]));
    return res;
}

ll Minor(int x,int y)
{
    ll res=5e7;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            std::swap(x,y);
        res=std::min(res,T::Minor(root,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        std::swap(x,y);
    res=std::min(res,T::Minor(root,dfn[x],dfn[y]));
    return res;
}

void Invert(int x,int y)
{
    T::path p;
    while(top[y]!=top[x])
    {
        p.push_back(T::pii(dfn[top[y]],dfn[y]));
        y=fa[top[y]];
    }
    p.push_back(T::pii(dfn[x],dfn[y]));
    reverse(p.begin(),p.end());
    T::Invert(root,p);
}

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    read(n),read(m),read(r);
    for(int i=1;i<n;++i)
    {
        int x,y;
        read(x),read(y);
        g[x].push_back(y),g[y].push_back(x);
    }
    dfs1(r,0);
    dfs2(r,r);
    T::min[0]=5e7;
    for(int i=1;i<=n;++i)
        root=T::merge(root,T::newnode(0));
    while(m--)
    {
        std::string cmd;
        std::cin>>cmd;
        if(cmd=="Increase")
        {
            int x,y,w;
            read(x),read(y),read(w);
            Increase(x,y,w);
        }
        else if(cmd=="Sum")
        {
            int x,y;
            read(x),read(y);
            printf("%lld\n",Sum(x,y));
        }
        else if(cmd=="Major")
        {
            int x,y;
            read(x),read(y);
            printf("%lld\n",Major(x,y));
        }
        else if(cmd=="Minor")
        {
            int x,y;
            read(x),read(y);
            printf("%lld\n",Minor(x,y));
        }
        else if(cmd=="Invert") // utilize the feature
        {
            int x,y;
            read(x),read(y);
            Invert(x,y);
        }
        else
            assert(0);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/10301287.html