【BZOJ1758】重建计划(点分治)
题意:
给定一棵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】重建计划(点分治)的更多相关文章
- [BZOJ1758][WC2010]重建计划(点分治+单调队列)
点分治,对于每个分治中心,考虑求出经过它的符合长度条件的链的最大权值和. 从分治中心dfs下去取出所有链,为了防止两条链属于同一个子树,我们一个子树一个子树地处理. 用s1[i]记录目前分治中心伸下去 ...
- [WC2010][BZOJ1758]重建计划-[二分+分数规划+点分治]
Description 传送门 Solution 看到那个式子,显然想到分数规划...(不然好难呢) 然后二分答案,则每条边的权值设为g(e)-ans.最后要让路径长度在[L,U]范围内的路径权值&g ...
- WC2010 BZOJ1758 重建计划_长链剖分
题目大意: 求长度$\in [L,U]$的路径的最大边权和平均值. 题解 首先二分就不用说了,分数规划大家都懂. 这题有非常显然的点分治做法,但还是借着这个题学一波长链剖分. 其长链剖分本身也没啥,就 ...
- P4292 [WC2010]重建计划 点分治+单调队列
题目描述 题目传送门 分析 看到比值的形式就想到 \(01分数规划\),二分答案 设当前的值为 \(mids\) 如果存在\(\frac{\sum _{e \in S} v(e)}{|S|} \geq ...
- 蒟蒻的长链剖分学习笔记(例题:HOTEL加强版、重建计划)
长链剖分学习笔记 说到树的链剖,大多数人都会首先想到重链剖分.的确,目前重链剖分在OI中有更加多样化的应用,但它大多时候是替代不了长链剖分的. 重链剖分是把size最大的儿子当成重儿子,顾名思义长链剖 ...
- 【BZOJ1758】【WC2010】重建计划(点分治,单调队列)
[BZOJ1758][WC2010]重建计划(点分治,单调队列) 题面 BZOJ 洛谷 Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表 ...
- BZOJ1758: [Wc2010]重建计划
题解: 这题我居然做了一星期?... 平均值的极值其实也可以算是一种分数规划,只不过分母上b[i]=1 然后我们就可以二分这个值.类似与 HNOI最小圈 如果没有 链的长度的限制的话,我们直接两遍df ...
- 「WC2010」重建计划(长链剖分/点分治)
「WC2010」重建计划(长链剖分/点分治) 题目描述 有一棵大小为 \(n\) 的树,给定 \(L, R\) ,要求找到一条长度在 \([L, R]\) 的路径,并且路径上边权的平均值最大 \(1 ...
- bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check
[Wc2010]重建计划 Time Limit: 40 Sec Memory Limit: 162 MBSubmit: 4345 Solved: 1054[Submit][Status][Disc ...
- BZOJ 1758 【WC2010】 重建计划
题目链接:重建计划 这道题现在已经成为一道板子题了…… 这是个非常显然的0-1分数规划,可以二分答案之后树分治判定一下.注意树分治的时候如果使用单调队列,需要把所有儿子预先按最大深度排好序,否则会被扫 ...
随机推荐
- windows deintall 12c client
1.unintall: close all oracle app C:\app\client\CICadmin\product\12.1.0\client_1\deinstall deinstall ...
- Codeforces Round #235 (Div. 2) D (dp)
以为是组合,后来看着像数位dp,又不知道怎么让它不重复用..然后就没思路 了. 其实状压就可以了 状压是可以确定一个数的使用顺序的 利用01也可以确定所有的数的使用以及不重复 dp[i+1<&l ...
- Vue 学习之el、template、replace和vue的生命周期 参考网址:https://segmentfault.com/a/1190000008010666
- ScrollView嵌套GridView,GridView显示不全
最近开发有个需求是以A-Z的方式区分全国城市(搜索功能),并实现字母索引的功能(有点类似微信,不过比较坑的是用的是GridView, 并且GridView上面还有几个LinearLayout). 详细 ...
- ERROR 1 (HY000): Can't create/write to file '/tmp/#sql_830_0.MYI' (Errcode: 13)
mysql操作时,出现报错. 执行describe 命令时, 临时文件目录没有创建或者无写入权限:于是: cd /var/lib/mysql/ #进入mysql数据目录 mkdir tmp #创建需要 ...
- 经典算法mark
在平时找工作的时候,或多或少会遇到一些算法问题,很多都是比较经典或者网上已经流传很久的.只是我们没有接触过,所以不知道怎么解决. 在这儿,我自己总结一些我遇到的一些经典算法,给自己增加一点记忆,也给需 ...
- vba,设置,excel,wps ,页面设置
全面认识页面设置之 PageSetup 对象我们在写 VBA 代码时,特别是做小型程序开发时,经常会用 VBA 来设置“页面设置”中的选项,还可用要用 VBA 来实现一些特殊的效果,这就需要使用 Pa ...
- 结对项目--黄金点游戏(邓乐&曾亮)
#include<stdio.h> #include<stdlib.h> #include<Windows.h> int result[100][1000000]; ...
- webstorm快捷键大全-webstorm常用快捷键
默认配置下的常用快捷键,提高代码编写效率,离不开快捷键的使用,Webstorm拥有丰富的代码快速编辑功能,你可以自由配置功能快捷键. Webstorm预置了其他编辑器的快捷键配置,可以点击 查找/代替 ...
- JavaScript 原生代码找对象的方法
1. id : document.getElementById('id') 2. 标签 : document.getElementsByTagName('标签') //获得的是一个标签数组 3. N ...