最近点 - 可持久化点分树 - 主席树

题目大意:给一棵树,点有黑白,每次形如翻转一个点颜色,询问到某个点的最近黑色点距离,以及返回之前某个版本。n,q<=1e5.
题解:显然将点分树可持久化一下,然后用一个可持久化堆(虽然写了个可持久化线段树)维护一下即可。点分树可持久化可以暴力拿个主席树维护点分树的点到堆的编号的映射,也可以将原树三度化之后直接可持久化,后者这部分复杂度一个log(但是并不很快)。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
    const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;
namespace OUTPUT_SPACE{
    char ss[100000*15],tt[20];int ssl,ttl;inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),ssl=0,0; }
    inline int print(int x) { if(!x) ss[++ssl]='0';for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');for(;ttl;ttl--) ss[++ssl]=tt[ttl];return ss[++ssl]='\n'; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::Flush;
const int N=200010,LOG=20,INF=1e9;struct edges{ int to,pre,w; }e[N<<1];int h[N],etop;vector<int> g[N];
inline int add_edge(int u,int v,int w) { return e[++etop].to=v,e[etop].w=w,e[etop].pre=h[u],h[u]=etop; }
inline int build_edge(int u,int v,int w) { return add_edge(u,v,w),add_edge(v,u,w); }
namespace SDH_space{
    int son[N],wf[N];
    inline int sdh(int x,int fa,int &nc)
    {
        int cnt=0,c;Rep(i,g[x]) if(g[x][i]^fa) sdh(g[x][i],x,nc);
        Rep(i,g[x]) if(g[x][i]^fa) son[++cnt]=g[x][i],wf[cnt]=1;
        while(cnt>2)
        {
            rep(i,(c=0)+1,cnt/2)
                nc++,build_edge(nc,son[i*2-1],wf[i*2-1]),
                build_edge(nc,son[i<<1],wf[i<<1]),son[++c]=nc,wf[c]=0;
            if(cnt&1) son[++c]=son[cnt],wf[c]=wf[cnt];cnt=c;
        }
        rep(i,1,cnt) build_edge(x,son[i],wf[i]);return 0;
    }
}
namespace MyHeap_space{
    const int T=3e7,max_range=1e5;int lc[T],rc[T],val[T],s[T],heap_node_cnt;
    inline int init() { return val[0]=INF; }
    inline int update(int &x,int y,int p,int v,int l=0,int r=max_range)
    {
        x=++heap_node_cnt,lc[x]=lc[y],rc[x]=rc[y],s[x]=s[y];
        int mid=(l+r)>>1;if(l==r) return s[x]+=v,val[x]=(s[x]?l:INF);
        if(p<=mid) update(lc[x],lc[y],p,v,l,mid);else update(rc[x],rc[y],p,v,mid+1,r);
        return val[x]=min(val[lc[x]],val[rc[x]]);
    }
    inline int query(int x) { return val[x]; }
}using MyHeap_space::update;using MyHeap_space::query;
namespace NODE_space{
    struct node{
        int g[3],rt[3],c,ans0;node() { g[0]=g[1]=g[2]=rt[0]=rt[1]=rt[2]=c=ans0=0; }
        inline int upd_from(const node &t,int dir,int dis,int sgn)
        {
            c=t.c;rep(i,0,c-1) g[i]=t.g[i],rt[i]=t.rt[i];
            return ans0=t.ans0,update(rt[dir],t.rt[dir],dis,sgn);
        }
        inline int ans(int k)const
        {
            int ans=INF;if(ans0) return 0;
            rep(i,0,c-1) if(i^k) ans=min(ans,query(rt[i]));
            return ans;
        }
    };
}using NODE_space::node;
namespace DFZ_space{
    const int T=3e6;node t[T];
    int sz[N],Lst[N],Lcnt,dir[N],d[N],vis[N];
    int dis[LOG][N],fr[LOG][N],rt[N],dfz_node_cnt;
    inline int getsz(int x,int fa=0)
    {
        sz[x]=1,Lst[++Lcnt]=x;
        for(int i=h[x],y;i;i=e[i].pre)
            if(!vis[y=e[i].to]&&e[i].to!=fa) sz[x]+=getsz(y,x);
        return sz[x];
    }
    inline int getrt(int &x)
    {
        for(int i=1,fsz=sz[x],tsz=fsz;i<=Lcnt;i++)
        {
            int y=Lst[i],ysz=fsz-sz[y];
            for(int j=h[y],z;j;j=e[j].pre)
                if(!vis[z=e[j].to]&&sz[e[j].to]<sz[y]) ysz=max(ysz,sz[z]);
            if(ysz<tsz) tsz=ysz,x=y;
        }
        return 0;
    }
    inline int getmsg(int x,int fa,int c,int d,int *dis,int *fr)
    {
        dis[x]=d,fr[x]=c;
        for(int i=h[x],y;i;i=e[i].pre)
            if(!vis[y=e[i].to]&&e[i].to!=fa) getmsg(y,x,c,d+e[i].w,dis,fr);
        return 0;
    }
    inline int dfz(int x,int dpt=0)
    {
        Lcnt=0,getsz(x),getrt(x),vis[x]=1,d[x]=dpt;int cnt=0;
        for(int i=h[x],y;i;i=e[i].pre) if(!vis[y=e[i].to])
            getmsg(y,x,cnt++,e[i].w,dis[dpt],fr[dpt]);
        for(int i=h[x],y;i;i=e[i].pre) if(!vis[y=e[i].to])
            t[x].g[t[x].c++]=dfz(y,dpt+1);
        return x;
    }
    inline int getdir(int x) { for(int i=d[x]-1;i>=0;i--) dir[i]=fr[i][x];return d[x]; }
    inline int upd(int x,int las,int cur,int sgn)
    {
        int r=rt[las],len=getdir(x),p=rt[cur]=++dfz_node_cnt;
        rep(i,0,len-1)
            t[p].upd_from(t[r],dir[i],dis[i][x],sgn),
            r=t[r].g[dir[i]],p=t[p].g[dir[i]]=++dfz_node_cnt;
        return t[p]=t[r],t[p].ans0^=1;
    }
    inline int qry(int x,int cur)
    {
        int ans=INF,p=rt[cur],len=getdir(x);
        rep(i,0,len-1) ans=min(ans,dis[i][x]+t[p].ans(fr[i][x])),p=t[p].g[dir[i]];
        return min(ans,t[p].ans(-1));
    }
}using DFZ_space::upd;using DFZ_space::qry;using DFZ_space::dfz;
namespace STA_space{
    const int T=3e6;
    int lc[T],rc[T],v[T],n,rt[N],sta_node_cnt;
    inline int build(int &x,int l,int r)
    {
        x=++sta_node_cnt;int mid=(l+r)>>1;if(l==r) return v[x]=-1;
        return build(lc[x],l,mid),build(rc[x],mid+1,r);
    }
    inline int build(int _n) { return n=_n,build(rt[0],1,n); }
    inline int update(int &x,int y,int p,int l,int r)
    {
        x=++sta_node_cnt;int mid=(l+r)>>1;lc[x]=lc[y],rc[x]=rc[y],v[x]=v[y];if(l==r) return v[x]*=-1;
        if(p<=mid) return update(lc[x],lc[y],p,l,mid);else return update(rc[x],rc[y],p,mid+1,r);
    }
    inline int upd_sta(int p,int x,int y) { return update(rt[y],rt[x],p,1,n); }
}using STA_space::upd_sta;
int main()
{
    int n=inn(),x,y,curt=0,tott=0;
    rep(i,1,n-1) x=inn(),y=inn(),g[x].pb(y),g[y].pb(x);
    MyHeap_space::init(),SDH_space::sdh(1,0,n),STA_space::build(n);
    DFZ_space::rt[0]=dfz(1),DFZ_space::dfz_node_cnt=n;
    for(int m=inn(),las_ans=0;m;m--)
    {
        int tp=inn(),x=inn()^las_ans;
        if(tp==1) tott++,upd(x,curt,tott,upd_sta(x,curt,tott)),curt=tott;
        else if(tp==2) print(las_ans=qry(x,curt));
        else curt=x;
    }
    return Flush(),0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值