AGC009D Uninity

一些无关紧要的事:

似乎很久没写题解了……象征性地更一篇。另外很多blog都设了私密,不是很敢公开,不过说不定哪天会公开的。

 

link

 

题意:

最优树的点分治:使得点分最大层数最小。(听说是经典问题)

$n\leq 10^5.$

 

题解:

性质+贪心。

给每个点按照高度标号(即从深度最深的开始标1,它的父亲标2,高度越高标号越大)。那么原问题可以转化为使得标号最大的点最小。

一个性质:原树上任意标号相同的两点间必存在一个标号大于它们的点。(显然,想象点分过程)

考虑自底向上给每个点编号。每个点维护一个bit[u][i]表示u子树内标号为i并且还未找到标号比它大的点的标号是否出现过。如果对于u的某两个儿子的子树中都出现了标号x,u至少要标x+1;如果u的某一个儿子的子树中出现了标号y,u一定不能标y。贪心找最小标号即可。

由于深度不超过log层(点分深度log层,这个肯定不能比点分更劣),复杂度$\mathcal{O}(n\log n)$。

 

code:

 1 #include<bits/stdc++.h>
 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++)
 3 #define per(i,x,y) for (int i=(x);i>=(y);i--)
 4 #define ll long long
 5 #define inf 1000000001
 6 #define y1 y1___
 7 using namespace std;
 8 char gc(){
 9     static char buf[100000],*p1=buf,*p2=buf;
10     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
11 }
12 #define gc getchar
13 ll read(){
14     char ch=gc();ll x=0;int op=1;
15     for (;!isdigit(ch);ch=gc()) if (ch=='-') op=-1;
16     for (;isdigit(ch);ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
17     return x*op;
18 }
19 #define N 100005
20 int n,cnt,head[N],bit[N][25],ans;
21 struct edge{int to,nxt;}e[N<<1];
22 void adde(int x,int y){e[++cnt].to=y;e[cnt].nxt=head[x];head[x]=cnt;}
23 void dfs(int u,int pr){
24     for (int i=head[u];i;i=e[i].nxt) if (e[i].to!=pr){
25         int v=e[i].to;
26         dfs(v,u);
27         rep (j,0,20) bit[u][j]+=bit[v][j];
28     }
29     int Min=0;
30     per (i,20,0) if (bit[u][i]>=2){Min=i+1;break;}
31     while (bit[u][Min]) Min++;
32     ans=max(ans,Min);
33     bit[u][Min]=1;
34     rep (i,0,Min-1) bit[u][i]=0;
35 }
36 int main(){
37     n=read();
38     rep (i,1,n-1){
39         int x=read(),y=read();
40         adde(x,y);adde(y,x);
41     }
42     dfs(1,0);
43     printf("%d\n",ans);
44     return 0;
45 }
View Code

 

posted @ 2018-08-17 10:21  bestfy  阅读(308)  评论(0编辑  收藏