zoukankan      html  css  js  c++  java
  • Codeforces 1320E. Treeland and Viruses 题解

    题目链接:E. Treeland and Viruses
    题目大意:有一棵有(n)个节点的树,(q)次询问(询问互相独立),每次给定(k_i)个颜色,每个颜色有一个起始点(v_j)和移动速度(s_j),每一个颜色在每一次操作中会使它周围没有被染色的连通块上与它的距离不超过(s_j)的点全部染为这一个颜色,每一轮中,颜色从(1)(k_i)依次开始操作,一直到所有点全部被染色为止,再询问(m_i)个关键点的颜色。


    题解:这一道题一看就像是建虚树,先考虑把虚树建出来,由于某些颜色会被阻断,所以不能够直接用树上路径长度求出,所以每一个点只能更新与它相邻的点,所以,先用孩子更新父亲,然后再用父亲更新孩子,这样做两遍之后就可以得出答案。至于依次染色的限制,可以直接用优先级解决掉(以到达时间为第一关键字,颜色种类为第二关键词)。思路还是挺简洁明了的。

    时间复杂度(O(n ext{log}n)),不过我的代码应该带上了一个很大的常数,如果用树链剖分求LCA应该会快不少。

    感觉自己的语文水平不太够啊,如果真的看不懂就看代码吧,代码应该也不难理解。

    下面是代码:

    #include <vector>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    void read(int &a){
    	a=0;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		a=(a<<1)+(a<<3)+(c^48);
    		c=getchar();
    	}
    }
    const int Maxn=200000;
    int head[Maxn+5],arrive[Maxn<<1|5],nxt[Maxn<<1|5],tot;
    void add_edge(int from,int to){
    	arrive[++tot]=to;
    	nxt[tot]=head[from];
    	head[from]=tot;
    }
    int n,q;
    int fa[18][Maxn+5];
    int dep[Maxn+5];
    int dfn[Maxn+5],out[Maxn+5],dfn_tot;
    void init_dfs(int u){
    	dfn[u]=++dfn_tot;
    	dep[u]=dep[fa[0][u]]+1;
    	for(int i=1;fa[i-1][fa[i-1][u]];i++){
    		fa[i][u]=fa[i-1][fa[i-1][u]];
    	}
    	for(int i=head[u];i;i=nxt[i]){
    		int v=arrive[i];
    		if(v==fa[0][u]){
    			continue;
    		}
    		fa[0][v]=u;
    		init_dfs(v);
    	}
    	out[u]=dfn_tot;
    }
    int find_lca(int u,int v){
    	if(dep[u]<dep[v]){
    		swap(u,v);
    	}
    	for(int i=17;i>=0;i--){
    		if(dep[fa[i][u]]>=dep[v]){
    			u=fa[i][u];
    		}
    	}
    	if(u==v){
    		return u;
    	}
    	for(int i=17;i>=0;i--){
    		if(fa[i][u]!=fa[i][v]){
    			u=fa[i][u];
    			v=fa[i][v];
    		}
    	}
    	return fa[0][u];
    }
    int find_dis(int u,int v){
    	return dep[u]+dep[v]-(dep[find_lca(u,v)]<<1);
    }//正常的倍增求LCA,树上距离等等
    int sp[Maxn+5],type[Maxn+5];
    int f[Maxn+5];
    int lim[Maxn<<2|5],lim_len;
    int pa[Maxn+5];
    int imp[Maxn+5];
    int st[Maxn+5],st_top;
    int get_time(int u,int v){
    	return (find_dis(u,v)+sp[type[u]]-1)/sp[type[u]];
    }//求出一个颜色的起始点到另一个点所需时间
    int merge(int u,int a,int b){
    	if(u==0){
    		return 0;
    	}
    	if(a==0){
    		return b;
    	}
    	if(b==0){
    		return a;
    	}
    	int dis_a=get_time(a,u),dis_b=get_time(b,u);
    	if(dis_a==dis_b){
    		return type[a]<type[b]?a:b;
    	}
    	return dis_a<dis_b?a:b;//双关键字
    }
    bool cmp(int p,int q){
    	return dfn[p]<dfn[q];
    }
    int main(){
    	read(n);
    	int u,v;
    	for(int i=1;i<n;i++){
    		read(u),read(v);
    		add_edge(u,v);
    		add_edge(v,u);
    	}
    	init_dfs(1);
    	read(q);
    	int k,m;
    	for(int i=1;i<=q;i++){
    		read(k),read(m);
    		lim_len=0;
    		for(int j=1;j<=k;j++){
    			read(u),read(v);
    			type[u]=j;
    			sp[j]=v;
    			f[u]=u;
    			lim[++lim_len]=u;
    		}
    		for(int j=1;j<=m;j++){
    			read(u);
    			lim[++lim_len]=u;
    			imp[j]=u;
    		}
    		sort(lim+1,lim+1+lim_len,cmp);
    		for(int j=lim_len-1;j>0;j--){
    			lim[++lim_len]=find_lca(lim[j],lim[j+1]);
    		}
    		sort(lim+1,lim+1+lim_len,cmp);
    		lim_len=unique(lim+1,lim+1+lim_len)-lim-1;
    		st_top=0;
    		for(int j=1;j<=lim_len;j++){
    			while(st_top&&out[st[st_top]]<dfn[lim[j]]){
    				st_top--;
    			}
    			if(st_top){
    				pa[lim[j]]=st[st_top];
    			}
    			st[++st_top]=lim[j];
    		}//普通的建虚树过程
    		for(int j=lim_len;j>0;j--){
    			f[pa[lim[j]]]=merge(pa[lim[j]],f[pa[lim[j]]],f[lim[j]]);
    		}//用孩子去更新父亲(往祖先染)
    		for(int j=1;j<=lim_len;j++){
    			f[lim[j]]=merge(lim[j],f[lim[j]],f[pa[lim[j]]]);
    		}//用父亲来更新孩子(往孩子染)
    		for(int j=1;j<=m;j++){
    			printf("%d ",type[f[imp[j]]]);
    		}
    		puts("");
    		for(int j=1;j<=lim_len;j++){
    			type[lim[j]]=0;
    			f[lim[j]]=0;
    			pa[lim[j]]=0;
    		}//一定要清零清零清零!!!!
    	}
    	return 0;
    }
    
  • 相关阅读:
    (转载)C++ string中find() ,rfind() 等函数 用法总结及示例
    UVA 230 Borrowers (STL 行读入的处理 重载小于号)
    UVA 12100 打印队列(STL deque)
    uva 12096 The SetStack Computer(STL set的各种库函数 交集 并集 插入迭代器)
    uva 1592 Database (STL)
    HDU 1087 Super Jumping! Jumping! Jumping!
    hdu 1176 免费馅饼
    HDU 1003 Max Sum
    转战HDU
    hust 1227 Join Together
  • 原文地址:https://www.cnblogs.com/withhope/p/12394858.html
Copyright © 2011-2022 走看看