[loj3014]独特的城市

注意到与$u$独特的点总是在距离$u$最远的点上,而直径的端点总包含距离$u$最远的点

换言之,设直径为$(a,b)$,则以$a,b$为根分别求出$u$到根路径上与$u$独特的点即可(仅在$u$较深的树上查询)

关于上述过程,可以维护一个栈,在递归$u$时依次执行以下过程:

1.弹出栈顶直至栈顶到$u$距离$>cmx$,在栈中加入$u$并递归$u$的长儿子

2.弹出栈顶直至栈顶到$u$距离$>mx$,并递归其余儿子(递归前若栈顶不为$u$则加入$u$)

3.(若栈顶为$u$)弹出栈顶的$u$,此时栈中的元素即为与$u$独特的点

(其中$cmx$为$u$轻儿子子树内距离$u$最远的点,$mx$为$u$子树内距离$u$最远的点)

关于正确性,注意在递归完$u$后栈并不需要还原,具体原因易得

关于复杂度,注意到$u$至多被插入$\deg(u)$次,因此均摊总复杂度为$o(n)$

在本问题中,还需要在栈变化时用一个桶维护其中特产数

时间复杂度为$o(n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 200005
 4 struct Edge{
 5     int nex,to;
 6 }edge[N<<1];
 7 stack<int>st;
 8 int E,n,m,x,y,a[N],head[N],dep[N],l[N],cl[N],mx[N],tot[N],ans[N];
 9 void add(int x,int y){
10     edge[E].nex=head[x];
11     edge[E].to=y;
12     head[x]=E++;
13 }
14 void dfs(int k,int fa,int s){
15     dep[k]=s;
16     mx[k]=l[k]=cl[k]=0;
17     for(int i=head[k];i!=-1;i=edge[i].nex)
18         if (edge[i].to!=fa){
19             dfs(edge[i].to,k,s+1);
20             int x=l[edge[i].to]+1;
21             if (l[k]<x){
22                 mx[k]=edge[i].to;
23                 swap(l[k],x);
24             }
25             cl[k]=max(cl[k],x);
26         }
27 }
28 void add(int k){
29     st.push(k);
30     if (++tot[a[k]]==1)ans[0]++;
31 }
32 void del(){
33     if (--tot[a[st.top()]]==0)ans[0]--;
34     st.pop();
35 }
36 void calc(int k,int fa){
37     if (fa)add(fa);
38     while ((!st.empty())&&(dep[k]-dep[st.top()]<=cl[k]))del();
39     if (mx[k])calc(mx[k],k);
40     while ((!st.empty())&&(dep[k]-dep[st.top()]<=l[k]))del();
41     ans[k]=max(ans[k],ans[0]);
42     for(int i=head[k];i!=-1;i=edge[i].nex)
43         if ((edge[i].to!=fa)&&(edge[i].to!=mx[k]))calc(edge[i].to,k);
44     if ((!st.empty())&&(st.top()==fa))del();
45 }
46 int main(){
47     scanf("%d%d",&n,&m);
48     memset(head,-1,sizeof(head));
49     for(int i=1;i<n;i++){
50         scanf("%d%d",&x,&y);
51         add(x,y);
52         add(y,x);
53     }
54     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
55     dfs(1,0,0);
56     x=1;
57     for(int i=2;i<=n;i++)
58         if (dep[x]<dep[i])x=i;
59     dfs(x,0,0);
60     calc(x,0);
61     x=1;
62     for(int i=2;i<=n;i++)
63         if (dep[x]<dep[i])x=i;
64     dfs(x,0,0);
65     calc(x,0);
66     for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
67 }
View Code

 

posted @ 2021-07-11 14:22  PYWBKTDA  阅读(61)  评论(0编辑  收藏  举报