题意:

给定一棵n个点的树,每条边有权值。
求一条链,这条链包含的边数在L和U之间,且平均边权最大。
N﹤=100000

思路:

做法一:RYZ作业

二分答案再点分治,寻找是否有大于0且边数在L和U之间的链

f[i]为当前子树深度为i的链最大总和,g[i]为前几个深度为i的链最大总和

维护一个下标递增,值递增的单调队列

按子树深度排序一定要加,因为清空与当前子树深度最大值有关,不加的话可能会退化成n^2

改了快一天改不出,还加了迭代,最后发现是分治的时候root打成v,相当于什么都没干……

 var head,vet,next,c,d,size,flag,q1:array[..]of longint;
p:array[..]of longint;
len,h,q2:array[..]of double;
f,g:array[..]of double;
n,i,tot,root,l1,r1,sum,mx,mxdep,x,y,z,tmp,t,w,now,m:longint;
eps,oo,mid:double; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; function max(x,y:longint):longint;
begin
if x>y then exit(x);
exit(y);
end; function min(x,y:longint):longint;
begin
if x<y then exit(x);
exit(y);
end; procedure add(a,b,c:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
len[tot]:=c;
head[a]:=tot;
end; procedure getroot(u,fa:longint);
var e,v:longint;
begin
size[u]:=; p[u]:=;
e:=head[u];
while e<> do
begin
v:=vet[e];
if (v<>fa)and(flag[v]=) then
begin
getroot(v,u);
size[u]:=size[u]+size[v];
p[u]:=max(p[u],size[v]);
end;
e:=next[e];
end;
p[u]:=max(p[u],sum-p[u]);
if p[u]<p[root] then root:=u;
end; procedure dfs(u,fa,dep:longint;t:double);
var e,v:longint;
begin
if f[dep]<t then f[dep]:=t;
mx:=max(mx,dep);
e:=head[u];
while e<> do
begin
v:=vet[e];
if (v<>fa)and(flag[v]=) then dfs(v,u,dep+,t+len[e]-mid);
e:=next[e];
end; end; procedure ins(k:longint;x:double);
begin
while (w>=t)and(q2[w]<x) do dec(w);
inc(w); q1[w]:=k; q2[w]:=x;
end; procedure del(k:longint);
begin
while (t<=w)and(q1[t]>=k) do inc(t);
end; procedure getdep(u,fa,dep:longint);
var e,v:longint;
begin
e:=head[u];
if dep>d[m] then d[m]:=dep;
while e<> do
begin
v:=vet[e];
if (v<>fa)and(flag[v]=) then getdep(v,u,dep+);
e:=next[e];
end;
end; procedure qsort(l,r:longint);
var i,j,mid:longint;
t:double;
begin
i:=l; j:=r; mid:=d[(l+r)>>];
repeat
while mid>d[i] do inc(i);
while mid<d[j] do dec(j);
if i<=j then
begin
swap(d[i],d[j]);
swap(c[i],c[j]);
t:=h[i]; h[i]:=h[j]; h[j]:=t;
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end; function solve(u:longint;avg:double):double;
var t1,t2,ans,tmp:double;
v,e,i,j:longint;
begin
t1:=avg; t2:=-oo;
m:=;
e:=head[u];
while e<> do
begin
v:=vet[e];
if flag[v]= then
begin
inc(m);
getdep(v,u,);
c[m]:=v; h[m]:=len[e];
end;
e:=next[e];
end;
if m> then qsort(,m);
while t1-t2>eps do
begin
t2:=t1; mid:=t1; ans:=-oo;
mxdep:=; g[]:=;
for j:= to m do
begin
v:=c[j];
mx:=;
dfs(v,u,,h[j]-mid);
t:=; w:=;
for i:=min(mxdep,r1) to l1 do ins(i,g[i]);
for i:=max(,l1-mxdep) to mx do
begin
if l1-i>= then ins(l1-i,g[l1-i]);
del(r1-i+);
if t<=w then
if (f[i]+q2[t])/(q1[t]+i)>ans then
ans:=(f[i]+q2[t])/(q1[t]+i);
end;
mxdep:=max(mxdep,mx);
for i:= to mx do
if f[i]>g[i] then g[i]:=f[i];
for i:= to mx do f[i]:=-oo;
end;
for i:= to mxdep do g[i]:=-oo;
t1:=t1+ans;
end;
flag[u]:=; t2:=t1;
e:=head[u];
while e<> do
begin
v:=vet[e];
if flag[v]= then
begin
root:=; sum:=size[v];
getroot(v,);
tmp:=solve(root,t1);
if tmp>t2 then t2:=tmp;
end;
e:=next[e];
end;
exit(t2); end; begin
assign(input,'bzoj1758.in'); reset(input);
assign(output,'bzoj1758.out'); rewrite(output);
readln(n);
readln(l1,r1);
oo:=1e8;
for i:= to n- do
begin
readln(x,y,z);
add(x,y,z);
add(y,x,z);
end;
p[]:=n+; root:=; sum:=n;
eps:=1e-4;
getroot(,);
for i:= to n do
begin
f[i]:=-oo; g[i]:=-oo;
end;
writeln(solve(root,)::);
close(input);
close(output);
end.

做法2:From https://blog.bill.moe/WC2010-rebuild/

建立一个答案表,顺序是长链剖分的dfs序

长链可以共用答案表,轻儿子暴力合并到父亲所在长链中

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> Pll;
typedef vector<int> VI;
typedef vector<PII> VII;
typedef pair<ll,int>P;
#define N 200010
#define M 200010
#define fi first
#define se second
#define MP make_pair
#define pi acos(-1)
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
#define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
#define lowbit(x) x&(-x)
#define Rand (rand()*(1<<16)+rand())
#define id(x) ((x)<=B?(x):m-n/(x)+1)
#define ls p<<1
#define rs p<<1|1 const ll MOD=1e9+,inv2=(MOD+)/;
double eps=1e-;
int INF=<<;
ll inf=5e13;
int dx[]={-,,,};
int dy[]={,,-,}; double t[N<<];
int head[N],vet[N],len[N],nxt[N],
dep[N],son[N],slen[N],fa[N],id[N],dfn[N],mx[N],top[N],
tot,L,R,tim,n;
double ans,tmp[N]; int read()
{
int v=,f=;
char c=getchar();
while(c<||<c) {if(c=='-') f=-; c=getchar();}
while(<=c&&c<=) v=(v<<)+v+v+c-,c=getchar();
return v*f;
} void add(int a,int b,int c)
{
nxt[++tot]=head[a];
vet[tot]=b;
len[tot]=c;
head[a]=tot;
} void build(int l,int r,int p)
{
t[p]=-1e18;
if(l==r)
{
id[l]=p;
return;
}
int mid=(l+r)>>;
build(l,mid,ls);
build(mid+,r,rs);
} void update(int u,double v)
{
int now=id[u];
while(now)
{
t[now]=max(t[now],v);
now>>=;
}
} double query(int l,int r,int x,int y,int p)
{
if(x<=l&&r<=y) return t[p];
int mid=(l+r)>>;
double res=-1e18;
if(x<=mid) res=max(res,query(l,mid,x,y,ls));
if(y>mid) res=max(res,query(mid+,r,x,y,rs));
return res;
} void dfs1(int u,int pre,int d)
{
dep[u]=mx[u]=d;
fa[u]=pre;
int e=head[u];
while(e)
{
int v=vet[e];
if(v!=pre)
{
dfs1(v,u,d+);
if(mx[v]>mx[son[u]])
{
son[u]=v;
slen[u]=len[e];
mx[u]=mx[v];
}
}
e=nxt[e];
}
} void dfs2(int u,int ance)
{
top[u]=ance;
dfn[u]=++tim;
if(son[u]) dfs2(son[u],ance);
int e=head[u];
while(e)
{
int v=vet[e];
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
e=nxt[e];
}
} double ask(int u,int l,int r)
{
l=max(l,);
r=min(r,mx[u]-dep[u]);
if(l>r) return -1e18;
return query(,n,dfn[u]+l,dfn[u]+r,);
} void solve(int u,double d,double mid)
{
update(dfn[u],d);
if(son[u]) solve(son[u],d+slen[u]-mid,mid);
int e=head[u];
while(e)
{
int v=vet[e];
if(v!=fa[u]&&v!=son[u])
{
solve(v,d+len[e]-mid,mid);
rep(j,,mx[v]-dep[v]+)
{
tmp[j]=t[id[dfn[v]+j-]];
ans=max(ans,tmp[j]+ask(u,L-j,R-j)-*d);
}
rep(j,,mx[v]-dep[v]+) update(dfn[u]+j,tmp[j]);
}
e=nxt[e];
}
ans=max(ans,ask(u,L,R)-d);
} int isok(double K)
{
build(,n,);
ans=-1e18;
solve(,,K);
return ans>=-eps;
} int main()
{
n=read(),L=read(),R=read();
tot=;
rep(i,,n-)
{
int x=read(),y=read(),z=read();
add(x,y,z);
add(y,x,z);
}
dfs1(,,);
tim=;
dfs2(,);
double left=,right=1e10;
while(right-left>eps)
{
double mid=(left+right)/;
if(isok(mid)) left=mid;
else right=mid;
}
printf("%.3f\n",left);
return ;
}

【BZOJ1758】重建计划(点分治)的更多相关文章

  1. [BZOJ1758][WC2010]重建计划(点分治+单调队列)

    点分治,对于每个分治中心,考虑求出经过它的符合长度条件的链的最大权值和. 从分治中心dfs下去取出所有链,为了防止两条链属于同一个子树,我们一个子树一个子树地处理. 用s1[i]记录目前分治中心伸下去 ...

  2. [WC2010][BZOJ1758]重建计划-[二分+分数规划+点分治]

    Description 传送门 Solution 看到那个式子,显然想到分数规划...(不然好难呢) 然后二分答案,则每条边的权值设为g(e)-ans.最后要让路径长度在[L,U]范围内的路径权值&g ...

  3. WC2010 BZOJ1758 重建计划_长链剖分

    题目大意: 求长度$\in [L,U]$的路径的最大边权和平均值. 题解 首先二分就不用说了,分数规划大家都懂. 这题有非常显然的点分治做法,但还是借着这个题学一波长链剖分. 其长链剖分本身也没啥,就 ...

  4. P4292 [WC2010]重建计划 点分治+单调队列

    题目描述 题目传送门 分析 看到比值的形式就想到 \(01分数规划\),二分答案 设当前的值为 \(mids\) 如果存在\(\frac{\sum _{e \in S} v(e)}{|S|} \geq ...

  5. 蒟蒻的长链剖分学习笔记(例题:HOTEL加强版、重建计划)

    长链剖分学习笔记 说到树的链剖,大多数人都会首先想到重链剖分.的确,目前重链剖分在OI中有更加多样化的应用,但它大多时候是替代不了长链剖分的. 重链剖分是把size最大的儿子当成重儿子,顾名思义长链剖 ...

  6. 【BZOJ1758】【WC2010】重建计划(点分治,单调队列)

    [BZOJ1758][WC2010]重建计划(点分治,单调队列) 题面 BZOJ 洛谷 Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表 ...

  7. BZOJ1758: [Wc2010]重建计划

    题解: 这题我居然做了一星期?... 平均值的极值其实也可以算是一种分数规划,只不过分母上b[i]=1 然后我们就可以二分这个值.类似与 HNOI最小圈 如果没有 链的长度的限制的话,我们直接两遍df ...

  8. 「WC2010」重建计划(长链剖分/点分治)

    「WC2010」重建计划(长链剖分/点分治) 题目描述 有一棵大小为 \(n\) 的树,给定 \(L, R\) ,要求找到一条长度在 \([L, R]\) 的路径,并且路径上边权的平均值最大 \(1 ...

  9. bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check

    [Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MBSubmit: 4345  Solved: 1054[Submit][Status][Disc ...

  10. BZOJ 1758 【WC2010】 重建计划

    题目链接:重建计划 这道题现在已经成为一道板子题了…… 这是个非常显然的0-1分数规划,可以二分答案之后树分治判定一下.注意树分治的时候如果使用单调队列,需要把所有儿子预先按最大深度排好序,否则会被扫 ...

随机推荐

  1. ASP.NET网站发布到服务器

    我们一个项目做好了之后想要上线,首先得发布,然后在上传到服务器. 所用到的工具:vs2013(其它vs版本也可以,大致上是一样的) FTP破解版下载链接:http://files.cnblogs.co ...

  2. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  3. css3中的变换、动画和过渡

    变换:分为2d变换和3d变换,但一次只能用一个变换属性,多个的话最后一个会覆盖前面所有最终被浏览器实现,变换可以成为过渡和动画的一个待变参数(类似width,opacity等). 过渡:是动画的初始模 ...

  4. 用unsigned char 表示字节

    在C中,默认的基础数据类型均为signed,现在我们以char为例,说明(signed) char与unsigned char之间的区别 首先在内存中,char与unsigned char没有什么不同 ...

  5. iOS Programming Web Services and UIWebView

    iOS Programming Web Services and UIWebView The work is divided into two parts. The first is connecti ...

  6. 【Linux】CentOS tar压缩与解压命令大全

    tar命令详解 -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用 ...

  7. JavaScript 原生代码找对象的方法

    1. id :  document.getElementById('id') 2. 标签 : document.getElementsByTagName('标签') //获得的是一个标签数组 3. N ...

  8. java_线程优先级

    线程优先级分为三个等级: MAX_PIORITY:10  优先 MIN_PRIORITY:1 NORM_PRIORITY:5  默认 getPriority:获取优先级 setPriority:设置优 ...

  9. 【C语言】控制台窗口图形界面编程(一)句柄和文本属性

    目录 00. 目录 01. 句柄 02. GetStdHandle函数 03. CloseHandle函数 04. SetConsoleTextAttribute函数 05. 十进制颜色对照表 06. ...

  10. js-时间戳转字符串

    function createTime(v){ var now = new Date(v); var yy = now.getFullYear(); //年 var mm = now.getMonth ...