zoukankan      html  css  js  c++  java
  • [BZO3572][HNOI2014]世界树:虚树+倍增

    分析

    思维难度几乎为(0)的虚树码农(并不)题。

    代码

    #include <bits/stdc++.h>
    #define rin(i,a,b) for(register int i=(a);i<=(b);++i)
    #define irin(i,a,b) for(register int i=(a);i>=(b);--i)
    #define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
    #define itrav(i,a) for(register int i=ihead[a];i;i=ie[i].nxt)
    typedef long long LL;
    using std::cin;
    using std::cout;
    using std::endl;
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int MAXN=3e5+5;
    
    int n,q,ecnt,head[MAXN];
    int tot,id[MAXN],num[MAXN],len,st[MAXN<<1][21],pos[MAXN];
    int dep[MAXN],siz[MAXN],anc[MAXN][21];
    int m,mm,h[MAXN<<1],hh[MAXN],top,sta[MAXN];
    int iecnt,ihead[MAXN];
    int ans[MAXN];
    bool isc[MAXN];
    
    struct Edge{
    	int to,nxt;
    }e[MAXN<<1];
    
    inline void add_edge(int bg,int ed){
    	++ecnt;
    	e[ecnt].to=ed;
    	e[ecnt].nxt=head[bg];
    	head[bg]=ecnt;
    }
    
    void dfs1(int x,int pre,int depth){
    	id[x]=++tot;
    	num[tot]=x;
    	st[++len][0]=id[x];
    	pos[x]=len;
    	dep[x]=depth;
    	siz[x]=1;
    	anc[x][0]=pre;
    	trav(i,x){
    		int ver=e[i].to;
    		if(ver==pre) continue;
    		dfs1(ver,x,depth+1);
    		st[++len][0]=id[x];
    		siz[x]+=siz[ver];
    	}
    }
    
    void buildst(){
    	int lim=log2(len);
    	rin(i,1,lim) rin(j,1,len-(1<<i)+1)
    		st[j][i]=std::min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
    }
    
    void buildanc(){
    	rin(i,1,20) rin(j,1,n)
    		anc[j][i]=anc[anc[j][i-1]][i-1];
    }
    
    inline int lca(int x,int y){
    	x=pos[x],y=pos[y];
    	if(x>y) std::swap(x,y);
    	int lim=log2(y-x+1);
    	return num[std::min(st[x][lim],st[y-(1<<lim)+1][lim])];
    }
    
    inline bool cmp(int x,int y){
    	return id[x]<id[y];
    }
    
    struct iedge{
    	int to,nxt;
    }ie[MAXN];
    
    inline void add_iedge(int bg,int ed){
    	++iecnt;
    	ie[iecnt].to=ed;
    	ie[iecnt].nxt=ihead[bg];
    	ihead[bg]=iecnt;
    }
    
    void build_itree(){
    	std::sort(h+1,h+m+1,cmp);
    	rin(i,2,mm) h[++m]=lca(h[i-1],h[i]);
    	h[++m]=1;
    	std::sort(h+1,h+m+1,cmp);
    	m=std::unique(h+1,h+m+1)-h-1;
    	top=0;
    	rin(i,1,m){
    		while(top&&id[h[i]]>id[sta[top]]+siz[sta[top]]-1) add_iedge(sta[top-1],sta[top]),--top;
    		sta[++top]=h[i];
    	}
    	while(top>1) add_iedge(sta[top-1],sta[top]),--top;
    	--top;
    }
    
    struct ctrl{
    	int pos,dis;
    	inline friend bool operator < (ctrl A,ctrl B){
    		return A.dis==B.dis?A.pos<B.pos:A.dis<B.dis;
    	}
    }c[MAXN];
    
    void dfs2(int x){
    	if(isc[x]) c[x]=(ctrl){x,0};
    	else c[x]=(ctrl){0,(int)1e9};
    	itrav(i,x){
    		int ver=ie[i].to;
    		dfs2(ver);
    		c[x]=std::min(c[x],(ctrl){c[ver].pos,c[ver].dis+dep[ver]-dep[x]});
    	}
    }
    
    void dfs3(int x,int pre){
    	if(pre) c[x]=std::min(c[x],(ctrl){c[pre].pos,c[pre].dis+dep[x]-dep[pre]});
    	itrav(i,x){
    		int ver=ie[i].to;
    		dfs3(ver,x);
    	}
    }
    
    inline int getveranc(int x,int pre){
    	int ret=x;
    	irin(i,20,0)
    		if(dep[anc[ret][i]]>dep[pre])
    			ret=anc[ret][i];
    	return ret;
    }
    
    inline int climb(int x,int y){
    	int ret=x,tt=0;
    	while(y){
    		if(y&1) ret=anc[ret][tt];
    		++tt;
    		y>>=1;
    	}
    	return ret;
    }
    
    void dfs4(int x,int pre){
    	ans[c[x].pos]+=siz[x];
    	itrav(i,x){
    		int ver=ie[i].to,veranc=getveranc(ver,x);
    		dfs4(ver,x);
    		ans[c[x].pos]-=siz[veranc];
    		if(c[x].pos==c[ver].pos)
    			ans[c[x].pos]+=siz[veranc]-siz[ver];
    		else{
    			int mid=0;
    			if((dep[ver]-dep[x]+c[ver].dis-c[x].dis)&1) mid=dep[ver]-(((dep[x]+dep[ver]+c[ver].dis-c[x].dis)>>1)+1);
    			else if(c[x].pos<c[ver].pos) mid=dep[ver]-(((dep[x]+dep[ver]+c[ver].dis-c[x].dis)>>1)+1);
    			else mid=dep[ver]-((dep[x]+dep[ver]+c[ver].dis-c[x].dis)>>1);
    			mid=climb(ver,mid);
    			ans[c[x].pos]+=siz[veranc]-siz[mid];
    			ans[c[ver].pos]+=siz[mid]-siz[ver];
    		}
    	}
    }
    
    /*
    const int MAXN=3e5+5;
    int n,q,ecnt,head[MAXN];
    int tot,id[MAXN],num[MAXN],len,st[MAXN<<1][21],pos[MAXN];
    int dep[MAXN],siz[MAXN],anc[MAXN][21];
    int m,mm,h[MAXN<<1],hh[MAXN],top,sta[MAXN];
    int iecnt,ihead[MAXN];
    int ans[MAXN];
    bool isc[MAXN];
    */
    
    void clear_itree(){
    	iecnt=0;
    	rin(i,1,m) ihead[h[i]]=ans[h[i]]=0,isc[h[i]]=false;
    }
    
    int main(){
    	n=read();
    	rin(i,2,n){
    		int u=read(),v=read();
    		add_edge(u,v);
    		add_edge(v,u);
    	}
    	dfs1(1,0,1);
    	buildst();
    	buildanc();
    	q=read();
    	while(q--){
    		m=mm=read();
    		rin(i,1,m) h[i]=hh[i]=read(),isc[h[i]]=true;
    		build_itree();
    		dfs2(1);
    		dfs3(1,0);
    		dfs4(1,0);
    		rin(i,1,mm) printf("%d ",ans[hh[i]]);
    		putchar('
    ');
    		clear_itree();
    	}
    	return 0;
    }
    
  • 相关阅读:
    MySQL事务学习-->隔离级别
    ssh升级
    通过普通用户向各个节点服务器分发文件到各个目录
    parted在2T以上硬盘上分区操作
    时间同步出现ntpdate[1788]: the NTP socket is in use, exiting
    kvm解决1000M网卡问题
    mysql主从同步问题解决汇总
    ....
    iOS App Icon图标 尺寸规范
    SpringMVC注解配置
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10382947.html
Copyright © 2011-2022 走看看