zoukankan      html  css  js  c++  java
  • 【BZOJ4539】【HNOI2016】—树(主席树)

    传送门

    真·树套树

    因为每次复制的都是原树的子树

    所以我们考虑直接在新树上加一个点来记录这是原树中的哪个点的子树
    边权设为儿子在父亲子树中连接的点到父亲的根的距离

    至于编号是一段连续的区间,可以直接记录每一段二分查找
    具体的点相当于原树子树中查找第kk大,一个主席树记录一下
    查询距离的时候先计算出u,v,lcau,v,lca三个根之间的距离

    然后分类讨论一下u,vu,vlcalca子树中连接的点之间的距离和真正点与根的距离

    复杂度O(nlogn)O(nlogn)
    实现可以看代码

    注意开long longlong long

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline int read(){
    	char ch=getchar();
    	int res=0,f=1;
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
    	return res*f;
    }
    inline ll readl(){
    	char ch=getchar();
    	ll res=0,f=1;
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
    	return res*f;
    }
    const int N=100005,Log=22;
    int in[N],out[N],dfn,n,m,q,idx,fa[N],rt[N];
    ll cnt[N];
    #define mid ((l+r)>>1)
    struct Pres_Tree{
    	int rt[N],siz[N*Log],lc[N*Log],rc[N*Log],tot;
    	void insert(int &u,int r1,int l,int r,int k){
    		u=++tot,siz[u]=siz[r1]+1,lc[u]=lc[r1],rc[u]=rc[r1];
    		if(l==r)return;
    		if(k<=mid)insert(lc[u],lc[r1],l,mid,k);
    		else insert(rc[u],rc[r1],mid+1,r,k);
    	}
    	inline void ins(int p,int k){insert(rt[p],rt[p-1],1,n,k);}
    	int query(int r1,int r2,int l,int r,int k){
    		if(l==r)return l;
    		int del=siz[lc[r2]]-siz[lc[r1]];
    		if(del>=k)return query(lc[r1],lc[r2],l,mid,k);
    		else return query(rc[r1],rc[r2],mid+1,r,k-del);
    	}
    	inline int qry(int l,int r,int k){return query(rt[l-1],rt[r],1,n,k);}
    }T;
    struct G{
    	int adj[N<<1],nxt[N<<1],to[N<<1],val[N<<1],dep[N],siz[N],f[N][Log],cnt;
    	ll dis[N];
    	inline void addedge(int u,int v,int w){
    		nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
    	}
    	inline void add(int u,int v,int w){
    		addedge(u,v,w),addedge(v,u,w);
    	}
    	void dfs1(int u){
    		for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
    		for(int e=adj[u];e;e=nxt[e]){
    			int v=to[e];
    			if(v==f[u][0])continue;
    			f[v][0]=u,dep[v]=dep[u]+1;
    			dis[v]=dis[u]+val[e],dfs1(v);
    		}
    	}
    	void dfs2(int u){
    		siz[u]=1,in[u]=++dfn,T.ins(dfn,u);
    		for(int e=adj[u];e;e=nxt[e]){
    			int v=to[e];
    			if(v==f[u][0])continue;
    			dfs2(v),siz[u]+=siz[v];	
    		}
    		out[u]=dfn;
    	}
    	inline int up(int u,int k){
    		for(int i=20;~i;i--){
    			if(k&(1<<i))u=f[u][i];
    		}
    		return u;
    	}
    	inline int Lca(int u,int v){
    		if(dep[u]<dep[v])swap(u,v);
    		u=up(u,dep[u]-dep[v]);
    		if(u==v)return u;
    		for(int i=20;~i;i--)
    		if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
    		return f[u][0];
    	}
    	inline ll dist(int u,int v){
    		return dis[u]+dis[v]-2ll*dis[Lca(u,v)];
    	}
    	inline int firson(int u,int v){
    		return up(u,dep[u]-dep[v]-1);
    	} 
    }A,B;
    inline int getid(ll u){
    	return lower_bound(cnt+1,cnt+idx+1,u)-cnt;
    }
    inline ll query(ll u,ll v){
    	int id1=getid(u),r1=rt[id1];u=T.qry(in[r1],out[r1],u-cnt[id1-1]);
    	int id2=getid(v),r2=rt[id2];v=T.qry(in[r2],out[r2],v-cnt[id2-1]);
    	int lca=B.Lca(id1,id2);
    	if(id1==id2)return A.dist(u,v);
    	ll res=B.dist(id1,id2)+A.dis[u]-A.dis[r1]+A.dis[v]-A.dis[r2];
    	if(id1==lca){
    		int fir=fa[B.firson(id2,id1)];
    		res-=(A.dis[u]-A.dis[r1])+(A.dis[fir]-A.dis[r1])-A.dist(u,fir);
    	}
    	else if(id2==lca){
    		int fir=fa[B.firson(id1,id2)];
    		res-=(A.dis[v]-A.dis[r2])+(A.dis[fir]-A.dis[r2])-A.dist(v,fir);
    	}
    	else{
    		int fira=fa[B.firson(id1,lca)],firb=fa[B.firson(id2,lca)];
    		res-=(A.dis[fira]-A.dis[rt[lca]]+A.dis[firb]-A.dis[rt[lca]]-A.dist(fira,firb));
    	}
    	return res;
    }
    signed main(){
    	n=read(),m=read(),q=read();
    	for(int i=1;i<n;i++){
    		int u=read(),v=read();
    		A.add(u,v,1);
    	}
    	A.dfs1(1),A.dfs2(1);
    	cnt[1]=n,idx=1,rt[1]=1;ll newn=n;
    	for(int i=2;i<=m+1;i++){
    		ll u=readl(),v=readl();
    		int id=getid(v),root=rt[id];
    		rt[i]=u,idx=i,fa[i]=T.qry(in[root],out[root],v-cnt[id-1]);
    		B.add(i,id,A.dis[fa[i]]-A.dis[root]+1);
    		newn+=A.siz[u],cnt[i]=newn;
    	}B.dfs1(1);
    	for(int i=1;i<=q;i++){
    		ll u=readl(),v=readl();
    		cout<<query(u,v)<<'
    ';
    	}
    }
    
  • 相关阅读:
    VTK初学一,动画加AVI录制终于做出来了
    QCamera获取摄像头图像(转载)
    VTK初学一,比较常见的错误2
    myeclipse2014鼠标单击后光标位置背景底色为白色太难看,行号显示
    记一次跟二房东公司(非中介个人房源无中介费)租房的经历
    求16进制数据或运算后的值(即多个16进制相加的和)
    error LNK2001: 无法解析的外部符号 "public: char * __thiscall
    如何利用指向数组的指针得到数组元素个数?
    C++判断字符串是否为空的一个小问题
    C++开发中BYTE类型数组转为对应的字符串
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145592.html
Copyright © 2011-2022 走看看