标签:display 分享图片 ini href 很多 main clu its names
似乎很久没写题解了……象征性地更一篇。另外很多blog都设了私密,不是很敢公开,不过说不定哪天会公开的。
最优树的点分治:使得点分最大层数最小。(听说是经典问题)
$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)$。
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 }
标签:display 分享图片 ini href 很多 main clu its names
原文地址:https://www.cnblogs.com/bestFy/p/9491887.html