zoukankan      html  css  js  c++  java
  • [HNOI2016]树

    https://www.luogu.org/problemnew/show/P3248

    题解

    模拟题意即可,把每次接过去的子树看做一个点,然后这个关系构成了一棵树。

    大力倍增即可。

    代码

    #include<bits/stdc++.h>
    #define N 100009
    #define ls tr[cnt].l
    #define rs tr[cnt].r
    using namespace std;
    typedef long long ll;
    int p[20][N],deep[N],tot,head[N],n,m,q,tott,dep[N],pr[20][N],T[N],size[N],c[N],pre[N];
    ll dis[20][N],noww,b[N],nowid;
    inline ll rd(){
    	ll x=0;char c=getchar();bool f=0;
    	while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f?-x:x;
    }
    struct node{
    	int l,r,size;
    }tr[N*40];
    struct edge{int n,to;}e[N<<1];
    inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
    inline void ins(int &cnt,int l,int r,int id){
    	cnt=++tott;
    	tr[cnt].size++;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(mid>=id)ins(ls,l,mid,id);
    	else ins(rs,mid+1,r,id);
    }
    int merge(int u,int v){
    	if(!u||!v)return u^v;
    	int cnt=++tott;
    	tr[cnt].size=tr[u].size+tr[v].size;
    	ls=merge(tr[u].l,tr[v].l);
    	rs=merge(tr[u].r,tr[v].r);
    	return cnt;
    } 
    inline int kth(int &cnt,int l,int r,int k){
    	int mid=(l+r)>>1;
    	if(l==r)return l;
    	if(tr[ls].size<k)return kth(rs,mid+1,r,k-tr[ls].size);
    	else return kth(ls,l,mid,k);
    }
    void dfs(int u,int fa){
    	ins(T[u],1,n,u);
    	size[u]=1;
    	for(int i=1;(1<<i)<=deep[u];++i)p[i][u]=p[i-1][p[i-1][u]];
    	for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
    		int v=e[i].to;deep[v]=deep[u]+1;p[0][v]=u;
    		dfs(v,u);
    		size[u]+=size[v];
    		T[u]=merge(T[u],T[v]); 
    	}
    }
    inline int getlca(int u,int v){
    	if(deep[u]<deep[v])swap(u,v);
    	for(int i=19;i>=0;--i)if(deep[u]-(1<<i)>=deep[v])u=p[i][u];
    	if(u==v)return u;
    	for(int i=19;i>=0;--i)if(p[i][u]!=p[i][v])u=p[i][u],v=p[i][v];
    	return p[0][u];
    }
    inline int jump(int x,int xx){
    	for(int i=19;i>=0;--i)if((1<<i)&xx)x=pr[i][x];
    	return x;
    }
    int main(){
    	n=rd();m=rd();q=rd();
    	ll u,v;
    	for(int i=1;i<n;++i){
    		u=rd();v=rd();
    		add(u,v);add(v,u);
    	}
    	dfs(1,0);
    	b[++b[0]]=1;noww=n;
    	c[b[0]]=1;
    	nowid=1;
    	while(m--){
    		u=rd();v=rd();
    		b[++b[0]]=noww+1;noww+=size[u];
    		c[b[0]]=u;
    		int x=upper_bound(b+1,b+b[0]+1,v)-b-1;
    		int preid=x,preroot=c[x],now=kth(T[preroot],1,n,v-b[x]+1);
    		//preid 被接的树的编号 preroot 被接的树的根 now被接的节点编号 
    	//	cout<<x<<" "<<preroot<<" "<<now<<" "<<preid<<" biu 
    "; 
    		++nowid;
    		pr[0][nowid]=preid;dis[0][nowid]=deep[now]-deep[preroot]+1;dep[nowid]=dep[preid]+1;
    		pre[nowid]=now;
    		for(int i=1;(1<<i)<=dep[nowid];++i)pr[i][nowid]=pr[i-1][pr[i-1][nowid]],
    		dis[i][nowid]=dis[i-1][nowid]+dis[i-1][pr[i-1][nowid]];
    	}
    	while(q--){
    		u=rd();v=rd();
    	    int x=upper_bound(b+1,b+b[0]+1,u)-b-1,y=upper_bound(b+1,b+b[0]+1,v)-b-1;
    	    int now1=kth(T[c[x]],1,n,u-b[x]+1),now2=kth(T[c[y]],1,n,v-b[y]+1);
    //		cout<<x<<" "<<y<<"  "<<now1<<" "<<now2<<endl;		
    		ll ans=0;
            if(x==y){
            	ans=deep[now1]+deep[now2]-2*deep[getlca(now1,now2)];
            	printf("%lld
    ",ans);
            	continue;
    		}
    		if(dep[x]<dep[y])swap(x,y),swap(now1,now2);
            int bu=dep[x]-dep[y];
            if(jump(x,bu)==y){
              int xx=bu-1;ans+=deep[now1]-deep[c[x]];		  
    		  for(int i=19;i>=0;--i)if((1<<i)&xx){
    			  ans+=dis[i][x];x=pr[i][x];
    		  }
    		  ans++;
    		  ans+=deep[now2]+deep[pre[x]]-2*deep[getlca(now2,pre[x])];
    		}
    		else{
    			ans+=deep[now1]-deep[c[x]]+deep[now2]-deep[c[y]];
    			for(int i=19;i>=0;--i)if(dep[x]-(1<<i)>=dep[y]){
    			  ans+=dis[i][x];x=pr[i][x];
    		     }
    			for(int i=19;i>=0;--i)if(pr[i][x]!=pr[i][y]){
    				ans+=dis[i][x]+dis[i][y];x=pr[i][x];y=pr[i][y];
    			}
    			int dx=pre[x],dy=pre[y];ans+=2;
    		//	cout<<x<<" "<<y<<" "<<pr[0][x]<<" "<<pr[0][y]<<"  ";
    			ans+=deep[dx]+deep[dy]-2*deep[getlca(dx,dy)];
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    innodb下ibd文件组成
    redo在ACID中作用,及一些概念
    mysql innodb安装目录下文件介绍: 日志记录redu/undo log及临时表ibtmp1
    mysql innodb引擎独立表空间记录,表组成及表迁移
    Python之函数、递归、内置函数
    Python之列表、字典、集合
    Python之介绍、基本语法、流程控制
    CSS之Bootstrap(快速布局)
    Django之缓存
    python之class面向对象(进阶篇)
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10829898.html
Copyright © 2011-2022 走看看