[BZOJ4573][UOJ#195][Zjoi2016][LCT][离线]大森林

1 篇文章 0 订阅

http://blog.csdn.net/lych_cys/article/details/53515748#
神想法啊…
至于求两点间距离为什么不能直接把两点的链拉出来
可以考虑因为树上虚点,两个点的LCA可以是一个虚点,虚点的父节点才是它们真正的LCA,所以直接拉一条链会导致少算一个点,而算LCA的话不会有这个问题(可以脑补一下)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#define N 100010

using namespace std;

int n,m,cnt,top,tot,g,cnt0;
int Ans[N],stc[N],L[N],R[N];
struct lef{
    int Size,rev,key;
    lef *ch[2],*fa;
    int isr(){ return (!fa)||(fa->ch[0]!=this&&fa->ch[1]!=this); }
    int isl(){ return fa&&fa->ch[1]==this; }
    void Up(){ Size=key+(ch[0]?ch[0]->Size:0)+(ch[1]?ch[1]->Size:0); }
    void reverse(){ access(); splay(); rev^=1; }
    void Push(){
        if(!rev) return ;
        swap(ch[0],ch[1]);
        if(ch[0]) ch[0]->rev^=1;
        if(ch[1]) ch[1]->rev^=1;
        rev=0;
    }
    lef *access(){
        lef *t,*x,*p; 
        for(t=0,x=this;x;x=x->fa)
            p=x,x->splay(),x->ch[1]=t,t=x,x->Up(); 
        return p;
    }
    void splay(){
        Pushtop();
        for(lef *x=this;!x->isr();x->rot())
            if(!x->fa->isr()) ((x->isl())^(x->fa->isl()))?x->rot():x->fa->rot();
    }
    void rot(){
        lef *x=this,*y=x->fa,*z=y->fa; int wh=x->isl();
        if(!y->isr()) z->ch[z->ch[1]==y]=x; x->fa=z;
        if(y->ch[wh]=x->ch[wh^1]) y->ch[wh]->fa=y;
        x->ch[wh^1]=y; y->fa=x; 
        y->Up(); x->Up();
    }
    void Pushtop(){ if(!isr()) this->fa->Pushtop(); Push(); }
}A[N<<2];
struct stp{int op,x,y,z,g;};
vector<stp> work[N];

inline void link(int x,int y){ A[x].reverse(); A[x].fa=&A[y]; A[x].access(); }
inline void cut(int x,int y){ A[x].reverse(); A[y].access(); A[y].splay(); A[y].ch[0]=A[x].fa=0; A[y].Up(); }
inline int query(int x,int y){
    int ret=0; lef *lca; A[1].reverse();
    A[x].access(); A[x].splay(); ret=A[x].Size;
    lca=A[y].access(); A[y].splay(); ret+=A[y].Size;
    lca->access(); lca->splay(); ret-=2*(lca->Size);
    return ret;
}

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p2==p1)?EOF:*p1++;
}

inline void rea(int &x){
    char c=nc(); x=0;
    for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline lef *newd(int x,int y){
    A[x].Size=y; A[x].ch[0]=A[x].ch[1]=A[x].fa=0; A[x].key=y;
    return &A[x];
}

int main(){
    rea(n); rea(m);
    newd(cnt=1,1); L[cnt]=1; R[cnt]=n;
    newd(tot=m+1,0); link(tot,cnt);
    for(int i=1;i<=m;i++){
        int op; rea(op);
        if(op==0){
            ++cnt; rea(L[cnt]); rea(R[cnt]);
            newd(cnt,1); link(cnt,tot);
        }
        else if(op==1){
            int l,r,x;
            rea(l); rea(r); rea(x);
            l=max(l,L[x]); r=min(r,R[x]);
            if(l<=r){
                newd(++tot,0); link(tot,tot-1);
                work[l].push_back((stp){1,tot,tot-1,x});
                work[r+1].push_back((stp){1,tot,x,tot-1});
            }
        }
        else{
            int x,y,z; rea(x); rea(y); rea(z);
            work[x].push_back((stp){2,x,y,z,++cnt0});
        }
    }
    for(int i=1;i<=n;i++){
        stp now;
        for(int j=0;j<work[i].size();j++){
            now=work[i][j];
            if(now.op==1){
                cut(now.x,now.y); link(now.x,now.z);
            }
            else
                Ans[now.g]=query(now.y,now.z);
        }
    }
    for(int i=1;i<=cnt0;i++) printf("%d\n",Ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值