BZOJ 3159 决战 (splay+树链剖分)

2 篇文章 0 订阅
2 篇文章 0 订阅

题意:给出一棵树,(1)路径加一个值;(2)路径上的节点的值反转(只是值反转,不是节点反转);(3)询问路径最大值 最小值 和。
解题思路:
题目简单,代码冗长
写这道题的时候还没有学LCT,所以我写了一种非常奇葩的方法,纯splay+树链剖分,代码冗长,但我觉得还挺好理解的。
首先我们可以先对整棵树进行树链剖分,分出轻重链之后就可以将一条链分解成若干条重链,用splay维护剖分出来的序列,查找最大最小和sum都是splay的基础操作就不说了,最关键的是进行树链翻转。这里的确让我为难了许久,后来我奇葩的想出了一个办法::将链按顺序提取出来合并然后进行反转再拆开按顺序放回去,这样就可以做到下一次查询这里正好是反过来的了,然后就是怎么做的问题了,这里的确变态,为了不改变点在序列的位置方便提取,我先按照这些条链在序列中从后往前提取,最后还要从前往后放回去,不过这里处理完之后就问题不大了,看着代码都是泪啊!!!
(代码核能,想看的话请做好心理准备)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
struct splay
{
    splay *ls,*rs,*fa;
    long long sum,maxx,minn,v,size;
    long long lazy_mark;
    bool rev_mark;
    splay(long long x);
    void push_up();
    void push_down();
    void add(long long x);
    void rev();
}*null=new splay(2000209123),*root,*midroot,*swz[100005];
long long t;
long long pou[100000];
long long fir[100005];
long long nex[100005];
long long wz[100000];
struct point
{
    long long top,son,fa,size,deep;
}a[100005];
struct bian
{
    long long l,r;
}b[100005];
void dfs1(int u,int fro)
{
    a[u].size=1;
    a[u].deep=a[fro].deep+1;
    for(int o=fir[u];o!=0;o=nex[o])
    {
        if(b[o].r!=fro)
        {
            a[b[o].r].fa=u;
            dfs1(b[o].r,u);
            a[u].size+=a[b[o].r].size;
            if(a[b[o].r].size>a[a[u].son].size) a[u].son=b[o].r;
        }
    }
}
void dfs2(int u,int fro)
{
    pou[++t]=u;
    wz[u]=t;
    if(u==a[a[u].fa].son) a[u].top=a[a[u].fa].top;
    else a[u].top=u;
    if(a[u].son) dfs2(a[u].son,u);
    for(int o=fir[u];o!=0;o=nex[o])
    {
        if(b[o].r!=fro && b[o].r!=a[u].son) dfs2(b[o].r,u);
    }
}
splay :: splay(long long x)
{
    ls=rs=fa=null;
    sum=maxx=minn=v=x;
    lazy_mark=rev_mark=0;
    size=null ? 1 : 0;
}
void splay :: add(long long x)
{
    if(this==null) return;
    lazy_mark+=x;
    push_down();
}
void splay :: rev()
{
    if(this==null) return;
    rev_mark^=1;
    push_down();
}
void splay :: push_up()
{
    if(ls!=null) ls->push_down();
    if(rs!=null) rs->push_down();
    size=ls->size+rs->size+1;
    maxx=0;
    if(ls->maxx>maxx && ls!=null && ls->v!=2000209123) maxx=ls->maxx;
    if(rs->maxx>maxx && rs!=null && rs->v!=2000209123) maxx=rs->maxx;
    if(v>maxx) maxx=v;
    minn=2147483647;
    if(ls->minn<minn && ls!=null && ls->v!=2000209123) minn=ls->minn;
    if(rs->minn<minn && rs!=null && rs->v!=2000209123) minn=rs->minn;
    if(v<minn) minn=v;
    sum=v;
    if(ls->v!=2000209123 && ls!=null) sum+=ls->sum;
    if(rs->v!=2000209123 && rs!=null) sum+=rs->sum;
}
void splay :: push_down()
{
    if(rev_mark)
    {
        swap(ls,rs);
        rev_mark=0;
        if(ls!=null && ls->v!=2000209123) ls->rev_mark^=1;
        if(rs!=null && rs->v!=2000209123) rs->rev_mark^=1;
    }
    if(lazy_mark)
    {
        v+=lazy_mark;
        minn+=lazy_mark;
        maxx+=lazy_mark;
        sum+=lazy_mark*size;
        if(ls!=null && ls->v!=2000209123) ls->lazy_mark+=lazy_mark;
        if(rs!=null && rs->v!=2000209123) rs->lazy_mark+=lazy_mark;
        lazy_mark=0;
    }
}
void left(splay *x)
{
    splay *y=x->fa;
    y->rs=x->ls;
    x->ls->fa=y;
    x->ls=y;
    x->fa=y->fa;
    if(y==y->fa->ls) y->fa->ls=x;
    else if(y==y->fa->rs) y->fa->rs=x;
    y->fa=x;
    y->push_up();
    if(y==root) root=x;
}
void right(splay *x)
{
    splay *y=x->fa;
    y->ls=x->rs;
    x->rs->fa=y;
    x->rs=y;
    x->fa=y->fa;
    if(y==y->fa->ls) y->fa->ls=x;
    else if(y==y->fa->rs) y->fa->rs=x;
    y->fa=x;
    y->push_up();
    if(y==root) root=x;
}
void splaying(splay *x,splay *goal)
{
    while(1)
    {
        splay *y=x->fa;
        splay *z=y->fa;
        if(y==goal) break;
        if(z==goal)
        {
            if(x==y->ls) right(x);
            else left(x);
            break;
        }
        if(x==y->ls)
        {
            if(y==z->ls) right(y);
            right(x);
        }
        else
        {
            if(y==z->rs) left(y);
            left(x);
        }
    }
    x->push_up();
}
void my_find(splay *x,long long mc,splay *z)
{
    while(1)
    {
        x->push_down();
        if(mc<=x->ls->size) x=x->ls;
        else
        {
            mc-=x->ls->size;
            if(mc==1) break;
            mc--;
            x=x->rs;
        }
    }
    splaying(x,z);
    midroot=x;
}
void add()
{
    long long x,y,v;
    scanf("%lld%lld%lld",&x,&y,&v);
    while(a[x].top!=a[y].top)
    {
        if(a[a[x].top].deep<a[a[y].top].deep) swap(x,y);
        my_find(root,wz[a[x].top],null);
        my_find(root,wz[x]+2,root);
        root->rs->ls->add(v);
        x=a[a[x].top].fa;
    }
    if(a[x].deep<a[y].deep) swap(x,y);
    my_find(root,wz[y],null);
    my_find(root,wz[x]+2,root);
    root->rs->ls->add(v);
    root->rs->push_up();
    root->push_up();
}
splay* maketree(long long l,long long r)
{
    if(l>r) return null;
    long long mid=l+r>>1;
    splay *sp=new splay(0);
    sp->ls=maketree(l,mid-1);
    sp->rs=maketree(mid+1,r);
    sp->ls->fa=sp->rs->fa=sp;
    sp->push_up();
    swz[mid]=sp;
    return sp;
}
void init()
{
    root=new splay(2000209123);
    root->rs=new splay(2000209123);
    root->rs->fa=root;
    root->rs->ls=maketree(1,t);
    root->rs->ls->fa=root->rs;
    root->rs->push_up();
    root->push_up();
}
int find_lca(int x,int y)
{
    while(a[x].top!=a[y].top)
    {
        if(a[a[x].top].deep<a[a[y].top].deep) swap(x,y);
        x=a[a[x].top].fa;
    }
    if(a[x].deep<a[y].deep) swap(x,y);
    return y;
}
void my_merge(splay* x,splay* y)
{
    my_find(x,x->size,null);
    midroot->rs=y;
    y->fa=midroot;
    midroot->push_up();
}
splay* tiqu(int l,int r,splay* &o)
{
    my_find(o,l,null);
    my_find(o,r+2,root);
    splay *mid=o->rs->ls;
    mid->fa=null;
    o->rs->ls=null;
    o->rs->push_up();
    o->push_up();
    return mid;
}
struct tiquchulaide
{
    int num,shou,len;
    splay* ti,*newti;
}midd[50000];
bool cmp1(tiquchulaide a,tiquchulaide b)
{
    return a.num<b.num;
}
bool cmp2(tiquchulaide a,tiquchulaide b)
{
    return a.shou>b.shou;
}
bool cmp3(tiquchulaide a,tiquchulaide b)
{
    return a.shou<b.shou;
}
int shou[50000];
int len[50000];
int top=0;
void y_find(int y,int lca)
{

    if(y==lca) return;
    if(a[y].top==a[lca].top)
    {
        shou[++top]=wz[lca]+1;
        len[top]=wz[y]-wz[lca];
        midd[top].num=top;
        midd[top].shou=shou[top];
        midd[top].len=len[top];
        return;
    }
    y_find(a[a[y].top].fa,lca);
    shou[++top]=wz[a[y].top];
    len[top]=wz[y]-wz[a[y].top]+1;
    midd[top].num=top;
    midd[top].shou=shou[top];
    midd[top].len=len[top];
}
void fanzhuanqujian()
{
    long long jilu=0;
    long long x,y;
    scanf("%lld%lld",&x,&y);
    top=0;
    long long lca=find_lca(x,y);
    while(x!=lca)
    {
        if(a[x].top==a[lca].top)
        {
            shou[++top]=wz[lca];
            len[top]=wz[x]-wz[lca]+1;
            midd[top].num=top;
            midd[top].shou=shou[top];
            midd[top].len=len[top];
            break;
        }
        shou[++top]=wz[a[x].top];
        len[top]=wz[x]-wz[a[x].top]+1;
        midd[top].num=top;
        midd[top].shou=shou[top];
        midd[top].len=len[top];
        x=a[a[x].top].fa;
    }
    jilu=top;
    if(x==lca)
    {
        shou[++top]=wz[lca];
        midd[top].shou=wz[lca];
        midd[top].len=1;
        midd[top].num=top;
        len[top]=1;
    }
    y_find(y,lca);
    sort(midd+1,midd+1+top,cmp2);
    for(int i=1;i<=top;i++)
    {
        midd[i].ti=tiqu(midd[i].shou,midd[i].shou+midd[i].len-1,root);
        if(midd[i].num<=jilu) midd[i].ti->rev();
    }
    sort(midd+1,midd+1+top,cmp1);
    midroot=null;

    for(int i=1;i<=top;i++)
    {
        //cout<<midroot->size<<" ";
        if(midroot==null) midroot=midd[i].ti;
        else my_merge(midroot,midd[i].ti);
    }
    //cout<<midroot->size<<endl;
    midroot->rev();
    for(int i=1;i<=top;i++)
    {
        //cout<<midroot->size<<endl;
        my_find(midroot,midd[i].len,null);
        //cout<<midd[i].shou<<" "<<midd[i].len<<endl;
        splay *middd=midroot->rs;
        middd->fa=null;
        midroot->rs=null;
        midroot->push_up();
        midd[i].newti=midroot;
        if(midd[i].num<=jilu) midd[i].newti->rev();
        midroot=middd;
    }
    sort(midd+1,midd+1+top,cmp3);
    for(int i=1;i<=top;i++)
    {
        my_find(root,midd[i].shou,null);
        my_find(root,midd[i].shou+1,root);
        root->rs->ls=midd[i].newti;
        root->rs->ls->fa=root->rs;
        root->rs->push_up();
        root->push_up();
    }
}
void sum()
{
    long long x,y;
    scanf("%lld%lld",&x,&y);
    long long ans=0;
    while(a[x].top!=a[y].top)
    {
        if(a[a[x].top].deep<a[a[y].top].deep) swap(x,y);
        my_find(root,wz[a[x].top],null);
        my_find(root,wz[x]+2,root);
        ans+=root->rs->ls->sum;
        x=a[a[x].top].fa;
    }
    if(a[x].deep<a[y].deep) swap(x,y);
    my_find(root,wz[y],null);
    my_find(root,wz[x]+2,root);
    ans+=root->rs->ls->sum;
    printf("%lld\n",ans);
}
void major()
{
    long long maxx=-214748364700000000ll;
    long long x,y;
    scanf("%d%d",&x,&y);
    long long ans=0;
    while(a[x].top!=a[y].top)
    {
        if(a[a[x].top].deep<a[a[y].top].deep) swap(x,y);
        my_find(root,wz[a[x].top],null);
        my_find(root,wz[x]+2,root);
        if(root->rs->ls->maxx>maxx) maxx=root->rs->ls->maxx;
        x=a[a[x].top].fa;
    }
    if(a[x].deep<a[y].deep) swap(x,y);
    my_find(root,wz[y],null);
    my_find(root,wz[x]+2,root);
    if(root->rs->ls->maxx>maxx) maxx=root->rs->ls->maxx;
    printf("%lld\n",maxx);
}
void minor()
{
    long long minn=214748364700000000ll;
    long long x,y;
    scanf("%lld%lld",&x,&y);
    long long ans=0;
    while(a[x].top!=a[y].top)
    {
        if(a[a[x].top].deep<a[a[y].top].deep) swap(x,y);
        my_find(root,wz[a[x].top],null);
        my_find(root,wz[x]+2,root);
        if(root->rs->ls->minn<minn) minn=root->rs->ls->minn;
        x=a[a[x].top].fa;
    }
    if(a[x].deep<a[y].deep) swap(x,y);
    my_find(root,wz[y],null);
    my_find(root,wz[x]+2,root);
    if(root->rs->ls->minn<minn) minn=root->rs->ls->minn;
    printf("%lld\n",minn);
}
char s[10];
int main()
{
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);
    long long n,m,r;
    scanf("%lld%lld%lld",&n,&m,&r);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&b[i].l,&b[i].r);
        b[n+i].l=b[i].r;
        b[n+i].r=b[i].l;
        nex[i]=fir[b[i].l];
        fir[b[i].l]=i;
        nex[n+i]=fir[b[i].r];
        fir[b[i].r]=n+i;
    }
    int t=rand()%n+1;
    dfs1(t,0);
    dfs2(t,0);
    init();
    //for(int i=1;i<=t;i++) cout<<wz[i]<<" ";
    for(int k=1;k<=m;k++)
    {
        scanf("%s",s);
        if(s[2]=='c') add();
        if(s[2]=='m') sum();
        if(s[2]=='j') major();
        if(s[2]=='n') minor();
        if(s[2]=='v') fanzhuanqujian();
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值