CF1320E Treeland and Viruses 题解

Codeforces
Luogu

Description.

多次询问,每次给出一些源点一些询问点。
多轮扩展,初始每个源点有它的颜色,每轮按照输入顺序依次扩展。
每次扩展所有到已是它颜色的距离不超过 \(s_i\) 的无色点,问询问点最后是什么颜色。

Solution.

多次直接套虚树,然后就变成了要求 \(O(\text{点数})\) 得到最后点是什么颜色。
考虑一个 \(O(Q\cdot m)\) 的做法,就是对于每个询问可以 \(O(m)\) 枚举。
对于一个询问的一个可行方案,可以 \(O(\log n)\)\(O(1)\) 求出颜色到它的时间。
然后就可以快速比较两种颜色的优先程度了。
考虑优化,如果一个颜色在某个地方已经被覆盖了,就可以不用考虑它了。
考虑一个颜色的覆盖路径,肯定是一条链,链又可以分成两段一段是上行一段是下行。

考虑记录当前这个点的颜色,然后从下到上更新父亲,从上到下更新儿子。
然后就做完了。

代码长度竟然主要是虚树,这是没想到的啊。。。

Coding.

点击查看太弱代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=200005;int n,Q,K,m,F[N],cl[N],idt,id[N<<2],sp[N],qr[N],fa[N],st[N],tp;
struct edge{int to,nxt;}e[N<<1];int et,head[N],f[N][20],dep[N],dt,dfn[N],sz[N];
inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
inline void dfs0(int x,int fa)
{
	dep[x]=dep[fa]+1,f[x][0]=fa,sz[x]=1,dfn[x]=++dt;
	for(int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1];
	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa)
		dfs0(e[i].to,x),sz[x]+=sz[e[i].to];
}
inline int LCA(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=19;~i;i--) if(dep[y]<=dep[f[x][i]]) x=f[x][i];
	for(int i=19;~i;i--) if(f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
	return x^y?f[x][0]:x;
}
inline int dis(int x,int y) {return dep[x]+dep[y]-(dep[LCA(x,y)]<<1);}
inline int tim(int x,int y) {return (dis(x,y)+sp[cl[x]]-1)/sp[cl[x]];}
inline void upd(int x,int &a,int b)
{
	if(!x) return;else if(!a||!b) return a=a|b,void();
	int d1=tim(a,x),d2=tim(b,x);if(d2<d1||(d1==d2&&cl[a]>cl[b])) a=b;
}
int main()
{
	read(n);for(int i=1,x,y;i<n;i++) read(x,y),adde(x,y),adde(y,x);
	for(dfs0(1,0),read(Q);Q--;)
	{
		read(K,m),idt=0;
		for(int i=1,x,w;i<=K;i++) read(x,w),cl[x]=i,sp[i]=w,F[x]=x,id[++idt]=x;
		for(int i=1,x;i<=m;i++) read(x),id[++idt]=x,qr[i]=x;
		sort(id+1,id+idt+1,[](int a,int b){return dfn[a]<dfn[b];});
		for(int i=idt;i>1;i--) id[++idt]=LCA(id[i],id[i-1]);
		sort(id+1,id+idt+1,[](int a,int b){return dfn[a]<dfn[b];});
		idt=unique(id+1,id+idt+1)-id-1,tp=0;
		for(int i=1;i<=idt;st[++tp]=id[i],i++)
		{
			while(tp&&dfn[st[tp]]+sz[st[tp]]<=dfn[id[i]]) tp--;
			if(tp) fa[id[i]]=st[tp];
		}
		//for(int i=1;i<=idt;i++) printf("%d%c",id[i],i==idt?'\n':' ');
		for(int i=idt;i>=2;i--) upd(fa[id[i]],F[fa[id[i]]],F[id[i]]);
		//for(int i=1;i<=idt;i++) printf("%d%c",F[id[i]],i==idt?'\n':' ');
		for(int i=2;i<=idt;i++) upd(id[i],F[id[i]],F[fa[id[i]]]);
		for(int i=1;i<=m;i++) printf("%d%c",cl[F[qr[i]]],i==m?'\n':' ');
		for(int i=1;i<=idt;i++) F[id[i]]=cl[id[i]]=fa[id[i]]=0,id[i]=0;
	}return 0;
}
原文地址:https://www.cnblogs.com/pealfrog/p/15321921.html