BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)
2015-11-22 12:46
375 查看
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758
01分数规划,所以我们对每个重心进行二分。于是问题转化为Σw[e]-mid>=0, 对于一棵子树维护点的dep,dis,并用队列q存下来。令mx[i]表示当前dep为i的最大权值,维护一个单调队列dq,维护当前符合条件的mx,当我们从q的队尾向前扫时,它的dep是递减的,利用这个性质维护单调队列,最后更新一遍mx。具体看代码吧TAT
代码:
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<queue>
#include<set>
#include<cmath>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 209000
#define inf int(1e9)
#define mm 1000000007
#define esp 1e-6
using namespace std;
#define ll long long
struct data{int obj,pre; double c;
}e[maxn*2];
int head[maxn],s[maxn],q[maxn],dq[maxn],dep[maxn],fa[maxn],vis[maxn];
double ans,lim,dis[maxn],mx[maxn];
int n,m,tot,sum,mn,rt,L,U;
int read(){
int x=0,f=1; char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
void insert(int x,int y,double z){
e[++tot].obj=y; e[tot].c=z; e[tot].pre=head[x]; head[x]=tot;
}
void dfs(int u,int fa){
s[u]=1; int mx=0;
for (int j=head[u];j;j=e[j].pre){
int v=e[j].obj;
if (v!=fa&&!vis[v]) {
dfs(v,u);
s[u]+=s[v];
mx=max(mx,s[v]);
}
}
mx=max(mx,sum-mx);
if (mx<mn) mn=mx,rt=u;
}
bool go(int u,double mid){
int up=0;
for (int j=head[u];j;j=e[j].pre){
int v=e[j].obj;
if (vis[v]) continue;
dep[v]=1; dis[v]=e[j].c-mid; fa[v]=u;
int l=0,r=1; q[1]=v;
while (l<r){
int now=q[++l];
for (int k=head[now];k;k=e[k].pre){
int v=e[k].obj;
if (v!=fa[now]&&!vis[v]){
fa[v]=now; dep[v]=dep[now]+1; dis[v]=dis[now]+e[k].c-mid;
q[++r]=v;
}
}
}
int tail=r; l=1; r=0; int now=up;
rep(i,1,tail){
while (dep[q[i]]+now>=L&&now>=0){
while (l<=r&&mx[now]>mx[dq[r]]) r--;
dq[++r]=now;
now--;
}
while (l<=r&&dep[q[i]]+dq[l]>U) l++;
if (l<=r&&dis[q[i]]+mx[dq[l]]>=0) return 1;
}
rep(i,up+1,dep[q[tail]]) mx[i]=-inf;
rep(i,1,tail) {
int now=dep[q[i]];
mx[now]=max(mx[now],dis[q[i]]);
}
up=max(up,dep[q[tail]]);
}
return 0;
}
void jud(int u){
double l=ans,r=lim;
while (r-l>=0.0001){
double mid=(l+r)/2;
if (go(u,mid)) l=mid;
else r=mid;
}
ans=l;
}
void solve(int u){
mn=inf;
dfs(u,0);
u=rt;
jud(u);
vis[u]=1;
for (int j=head[u];j;j=e[j].pre){
int v=e[j].obj;
if (!vis[v]) {
sum=s[v];
if (sum>L) solve(v);
}
}
}
int main(){
n=read();
L=read(); U=read();
int x,y; double z;
rep(i,1,n-1){
x=read(); y=read(); scanf("%lf",&z);
insert(x,y,z);
insert(y,x,z);
lim=max(lim,z);
}
sum=n;
solve(1);
printf("%.3lf\n",ans);
return 0;
}
01分数规划,所以我们对每个重心进行二分。于是问题转化为Σw[e]-mid>=0, 对于一棵子树维护点的dep,dis,并用队列q存下来。令mx[i]表示当前dep为i的最大权值,维护一个单调队列dq,维护当前符合条件的mx,当我们从q的队尾向前扫时,它的dep是递减的,利用这个性质维护单调队列,最后更新一遍mx。具体看代码吧TAT
代码:
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<queue>
#include<set>
#include<cmath>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 209000
#define inf int(1e9)
#define mm 1000000007
#define esp 1e-6
using namespace std;
#define ll long long
struct data{int obj,pre; double c;
}e[maxn*2];
int head[maxn],s[maxn],q[maxn],dq[maxn],dep[maxn],fa[maxn],vis[maxn];
double ans,lim,dis[maxn],mx[maxn];
int n,m,tot,sum,mn,rt,L,U;
int read(){
int x=0,f=1; char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
void insert(int x,int y,double z){
e[++tot].obj=y; e[tot].c=z; e[tot].pre=head[x]; head[x]=tot;
}
void dfs(int u,int fa){
s[u]=1; int mx=0;
for (int j=head[u];j;j=e[j].pre){
int v=e[j].obj;
if (v!=fa&&!vis[v]) {
dfs(v,u);
s[u]+=s[v];
mx=max(mx,s[v]);
}
}
mx=max(mx,sum-mx);
if (mx<mn) mn=mx,rt=u;
}
bool go(int u,double mid){
int up=0;
for (int j=head[u];j;j=e[j].pre){
int v=e[j].obj;
if (vis[v]) continue;
dep[v]=1; dis[v]=e[j].c-mid; fa[v]=u;
int l=0,r=1; q[1]=v;
while (l<r){
int now=q[++l];
for (int k=head[now];k;k=e[k].pre){
int v=e[k].obj;
if (v!=fa[now]&&!vis[v]){
fa[v]=now; dep[v]=dep[now]+1; dis[v]=dis[now]+e[k].c-mid;
q[++r]=v;
}
}
}
int tail=r; l=1; r=0; int now=up;
rep(i,1,tail){
while (dep[q[i]]+now>=L&&now>=0){
while (l<=r&&mx[now]>mx[dq[r]]) r--;
dq[++r]=now;
now--;
}
while (l<=r&&dep[q[i]]+dq[l]>U) l++;
if (l<=r&&dis[q[i]]+mx[dq[l]]>=0) return 1;
}
rep(i,up+1,dep[q[tail]]) mx[i]=-inf;
rep(i,1,tail) {
int now=dep[q[i]];
mx[now]=max(mx[now],dis[q[i]]);
}
up=max(up,dep[q[tail]]);
}
return 0;
}
void jud(int u){
double l=ans,r=lim;
while (r-l>=0.0001){
double mid=(l+r)/2;
if (go(u,mid)) l=mid;
else r=mid;
}
ans=l;
}
void solve(int u){
mn=inf;
dfs(u,0);
u=rt;
jud(u);
vis[u]=1;
for (int j=head[u];j;j=e[j].pre){
int v=e[j].obj;
if (!vis[v]) {
sum=s[v];
if (sum>L) solve(v);
}
}
}
int main(){
n=read();
L=read(); U=read();
int x,y; double z;
rep(i,1,n-1){
x=read(); y=read(); scanf("%lf",&z);
insert(x,y,z);
insert(y,x,z);
lim=max(lim,z);
}
sum=n;
solve(1);
printf("%.3lf\n",ans);
return 0;
}
相关文章推荐
- 项目中页面未找到统一跳转到一个notfound页面
- 【转载】Animation 动画(一)alpha、scale、translate、rotate、set的xml属性及用法
- 2014传智播客C++第三期基础班+就业班至9月份 完整版
- android中实现view可以滑动的六种方法续篇(一)
- Android图片上传蒙层进度条
- 如何在Cocos2D游戏中实现A*寻路算法(五)
- 如何在Cocos2D游戏中实现A*寻路算法(五)
- 如何在Cocos2D游戏中实现A*寻路算法(五)
- 解决ubuntu 下virtualbox 装ubuntu屏幕大小问题
- 正则表达式匹配问题
- 安装visual assist x 2083出现security key required问题
- HDMI和AV输入编码器成功了
- MySQL Drop 大表解决方案
- linux日常管理-防火墙selinux
- LOCATION BLOCK 匹配规则
- sicily 1132. ROUTES
- Android四大组件Service之bindService启动
- hdu 1080 带权值的 最长公共子序列 动态规划
- 持续交付团队该如何做重构
- xiaoit博客