题目
不敢挂LG。点分治常数太大洛谷上过不了。。。。
1.直接求边数为
l
l
l的路径的最大路径长度,这个点分治做不了。
因为合并答案的时候是
O
(
n
2
)
O(n^2)
O(n2)跑不掉的。
唯一的特例是你写FFT。
和
和
和卷积?不存在的。
2.二分答案判定有无
[
L
,
U
]
[L,U]
[L,U]的路径长度大于边数*二分的答案。
在子树合并时相当于从小到大枚举一个子树深度,另一个子树深度的上限和下限都下降,求最大值,可以用单调队列。
3.需要把子树的深度从小到大排序,这样每次合并的复杂度就是新加入的子树高度,总复杂度
O
(
n
)
O(n)
O(n)。
4.为啥
O
(
n
log
2
n
)
O(n \log ^2 n)
O(nlog2n)的算法跑
1
0
5
10^5
105还这么吃力啊,实数二分答案的常数果然还是太大了。
#include<bits/stdc++.h>
#define maxn 100005
#define LG 20
#define inf 1e15
#define F first
#define S second
#define eps 1e-4
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,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,Lb,Ub;
int dep[maxn],siz[maxn],zdep[maxn];
vector<pair<int,int> >G[maxn];
int rt , Min;
void dfs(int now,int ff,int tsz,int lim){
int Max = 0;siz[now] = 1;
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if((v=G[now][i].F)!=ff && dep[v]>=lim)
dfs(v,now,tsz,lim),
siz[now] += siz[v],
Max = max(Max , siz[v]);
Max = max(Max , tsz - siz[now]);
if(Min > Max) Min = Max , rt = now;
}
int findrt(int now,int tsz,int lim){
rt = -1 , Min = 0x3f3f3f3f;
dfs(now , 0 , tsz , lim);
return rt;
}
void serdep(int now,int ff,int lim,int Dep){
zdep[now] = Dep , siz[now] = 1;
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if(dep[v=G[now][i].F]>lim && v!=ff){
serdep(v,now,lim,Dep+1);
zdep[now] = max(zdep[now] , zdep[v]);
siz[now] += siz[v];
}
}
bool cmp(const pair<int,int> &u,const pair<int,int> &v){ return zdep[u.F] < zdep[v.F]; }
void Solve(int now,int lim){
dep[now] = lim;
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if(dep[v=G[now][i].F] > lim)
serdep(v,now,lim,1);
sort(G[now].begin(),G[now].end(),cmp);
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if(dep[v=G[now][i].F]>lim)
Solve(findrt(v,siz[v],lim+1),lim+1);
}
double dis[2][maxn];
int l1 , l2;
void ser(int now,int ff,int lim,double dist,int Dep,double ct){
if(Dep > Ub) return;
dis[1][Dep] = max(dis[1][Dep] , dist);
l2 = max(l2 , Dep);
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if(dep[v=G[now][i].F] > lim && v!=ff)
ser(v,now,lim,dist+G[now][i].S-ct,Dep+1,ct);
}
bool check(double mid){
static int q[maxn],L,R;
for(int i=0;i<=n;i++) dis[0][i] = dis[1][i] = -inf;
for(int i=1;i<=n;i++){
for(int j=l1;j>=0;j--) dis[0][j] = -inf;
l1 = dis[0][0] = 0;
for(int j=0,sz=G[i].size(),v;j<sz;j++)
if(dep[v=G[i][j].F] > dep[i]){
for(int k=l2;k>=0;k--) dis[1][k] = -inf;
l2 = 0;
ser(v,i,dep[i],G[i][j].S-mid,1,mid);
L = R = 0;
for(int p1=1,p2=l1;p2>=0;p2--){
for(;p1<=l2 && p1+p2<=Ub;p1++){
for(;L<R && dis[1][q[R-1]] < dis[1][p1];R--);
q[R++] = p1;
}
for(;L<R && q[L]+p2<Lb;L++);
if(L<R && dis[1][q[L]] + dis[0][p2] >= 0)
return 1;
}
for(int k=1;k<=l2;k++)
dis[0][k] = max(dis[0][k] , dis[1][k]);
l1 = l2;
}
}
return 0;
}
int main(){
//freopen("1.in","r",stdin);
memset(dep,0x3f,sizeof dep);
read(n),read(Lb),read(Ub);
for(int i=1;i<n;i++){
int u,v,w;
read(u),read(v),read(w);
G[u].push_back(make_pair(v,w));
G[v].push_back(make_pair(u,w));
}
Solve(findrt(1,n,1),1);
double L=0 , R=1000000,mid;
for(;L<R-eps;){
mid = (L+R) * 0.5;
if(check(mid)) L = mid;
else R = mid - eps;
}
printf("%.3lf\n",L);
}
upd:对着LG Rank1的代码写了分迭代,快的亲妈都不认识了。。。。。。
实测对于随机数据迭代次数基本等于1。
AC Code:
#include<bits/stdc++.h>
#define maxn 100005
#define LG 20
#define inf 1e15
#define F first
#define S second
#define eps 1e-4
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,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,Lb,Ub;
int dep[maxn],siz[maxn],zdep[maxn];
vector<pair<int,int> >G[maxn];
int rt , Min;
void dfs(int now,int ff,int tsz,int lim){
int Max = 0;siz[now] = 1;
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if((v=G[now][i].F)!=ff && dep[v]>=lim)
dfs(v,now,tsz,lim),
siz[now] += siz[v],
Max = max(Max , siz[v]);
Max = max(Max , tsz - siz[now]);
if(Min > Max) Min = Max , rt = now;
}
int findrt(int now,int tsz,int lim){
rt = -1 , Min = 0x3f3f3f3f;
dfs(now , 0 , tsz , lim);
return rt;
}
void serdep(int now,int ff,int lim,int Dep){
zdep[now] = Dep , siz[now] = 1;
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if(dep[v=G[now][i].F]>lim && v!=ff){
serdep(v,now,lim,Dep+1);
zdep[now] = max(zdep[now] , zdep[v]);
siz[now] += siz[v];
}
}
bool cmp(const pair<int,int> &u,const pair<int,int> &v){ return zdep[u.F] < zdep[v.F]; }
void Solve(int now,int lim){
dep[now] = lim;
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if(dep[v=G[now][i].F] > lim)
serdep(v,now,lim,1);
sort(G[now].begin(),G[now].end(),cmp);
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if(dep[v=G[now][i].F]>lim)
Solve(findrt(v,siz[v],lim+1),lim+1);
}
double dis[2][maxn];
int l1 , l2;
void ser(int now,int ff,int lim,double dist,int Dep,double ct){
dis[1][Dep] = max(dis[1][Dep] , dist);
l2 = max(l2 , Dep);
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if(dep[v=G[now][i].F] > lim && v!=ff)
ser(v,now,lim,dist+G[now][i].S-ct,Dep+1,ct);
}
double Ans;
void check(double mid){
Ans = -inf;
static int q[maxn],L,R;
for(int i=0;i<=n;i++) dis[0][i] = dis[1][i] = -inf;
for(int i=1;i<=n;i++){
for(int j=l1;j>=0;j--) dis[0][j] = -inf;
l1 = dis[0][0] = 0;
for(int j=0,sz=G[i].size(),v;j<sz;j++)
if(dep[v=G[i][j].F] > dep[i]){
for(int k=l2;k>=0;k--) dis[1][k] = -inf;
l2 = 0;
ser(v,i,dep[i],G[i][j].S-mid,1,mid);
L = R = 0;
for(int p1=1,p2=l1;p2>=0;p2--){
for(;p1<=l2 && p1+p2<=Ub;p1++){
for(;L<R && dis[1][q[R-1]] < dis[1][p1];R--);
q[R++] = p1;
}
for(;L<R && q[L]+p2<Lb;L++);
if(L<R)
Ans = max(Ans , (dis[1][q[L]] + dis[0][p2] + mid * (p2 +q[L])) / (p2 + q[L]));
}
for(int k=1;k<=l2;k++)
dis[0][k] = max(dis[0][k] , dis[1][k]);
l1 = l2;
}
}
}
int main(){
freopen("1.in","r",stdin);
memset(dep,0x3f,sizeof dep);
read(n),read(Lb),read(Ub);
for(int i=1;i<n;i++){
int u,v,w;
read(u),read(v),read(w);
G[u].push_back(make_pair(v,w));
G[v].push_back(make_pair(u,w));
}
Solve(findrt(1,n,1),1);
double mid=500000;
for(;;){
check(mid);
printf("%.3lf %.3lf\n",mid,Ans);
if(fabs(mid - Ans) < 1e-4) break;
mid = Ans;
}
printf("%.3lf\n",Ans);
}