「JOI 2019 Final」獨特的城市(長鏈剖分)

題目

發現答案一定在直徑上,然後以直徑端點爲根求出每個點的長兒子,然後dfsdfs一下即可求出每個點的答案。

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 200005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
void read(int &res){
	char ch;
	for(;!isdigit(ch=getc()););
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}

int n,m,cl[maxn],c[maxn],ans[maxn];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }

int S,T,dis[maxn];

void dfs0(int u,int ff,int d,int &s){
	dis[u] = d;
	if(d > dis[s]) s = u;
	for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff)
		dfs0(v,u,d+1,s);
}

int son[maxn] , len[maxn],dep[maxn]; 
void dfs1(int u,int ff){
	son[u] = len[u] = 0;
	dep[u] = dep[ff] + 1;
	for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff)
		dfs1(v,u) , (len[v] > len[son[u]]) && (son[u] = v);
	len[u] = len[son[u]] + 1;
}

int sta[maxn],tp,tr,sm;
void dfs2(int u,int ff){
	for(;tr < tp && dep[u] - dep[sta[tr+1]] > len[u] - 1;)
		sm += (c[cl[sta[++tr]]]++ == 0);
	ans[u] = max(ans[u] , sm);
	if(son[u]){
		int sl = 0;
		for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff && v!=son[u]) 
			sl = max(sl , len[v]);
		for(;tp && dep[u] - dep[sta[tp]] <= sl;tp--)
			if(tr == tp)
				sm -= (--c[cl[sta[tr--]]] == 0);
		sta[++tp] = u;
		dfs2(son[u],u);
		for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff && v!=son[u]){
			for(;tp && dep[u] - dep[sta[tp]] <= len[u] - 1;tp--)
				if(tr == tp)
					sm -= (--c[cl[sta[tr--]]] == 0);
			if(sta[tp] != u) sta[++tp] = u;
			dfs2(v,u);
		}
	}
}

void Solve(int s){
	tp = tr = sm = 0;
	memset(c,0,sizeof c);
	dfs1(s,0);
	dfs2(s,0);
}

int main(){
	read(n),read(m);
	rep(i,1,n-1){
		int u,v;read(u),read(v);
		Node(u,v),Node(v,u);
	}
	rep(i,1,n) read(cl[i]);
	memset(dis,-1,sizeof dis);
	dfs0(1,0,0,S);
	memset(dis,-1,sizeof dis);
	dfs0(S,0,0,T);
	
	Solve(S);
	Solve(T);
	rep(i,1,n) printf("%d\n",ans[i]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章