bzoj1758重建计划,树的点分治+单调队列(可能是常见套路?)
来源:互联网 发布:截面数据统计分析方法 编辑:程序博客网 时间:2024/05/20 13:36
传送门
似乎这题有很多种做法。
我的做法是, 先二分答案,然后再分治,这样,如果一开始就找到了路,就能很快返回。然而点分时找重心的常数比较大,我又是每次重新dfs,而不是再次利用前面的结果,然后就跑得很慢。
分治时,我是将每课子树,每个(不带权的)深度中取出(带权深度)最大的一个,组成一个数组a,先求解,把前面的结果组成一个单调队列,用双指针扫,再和前面的暴力合并,处理时我按子树深度排了个序,从小到大处理,这样,每次合并时,操作次数为所有子树的深度和,然后所有子树的深度和<=所有子树的大小=
假如不按深度从小到大处理,而是任意顺序,那么对于一条链,链的一端是一朵菊花,处理分治中心为菊花花心时就会爆炸。
#include<cstdio>#include<cstring>#include<algorithm>#include<cctype> using namespace std;typedef long long ll;typedef double db;const int N=100005;const db eps=1e-4;inline void up(db&a,db b){ if(a<b)a=b;}inline void up(int&a,int b){ if(a<b)a=b;}inline int min(int a,int b){ return a>b?b:a;}int n,u,v,w,i,L,U;db l,r,m;struct tree{ struct edge{ int to,next,w; db c; }e[N<<1]; int xb,h[N],rt,sum,sz[N],f[N],w,dd,z,q[N],tt,ww; db a[N],m[N],len[N]; bool b[N]; struct node{ int v,l,r; bool operator<(const node&x)const{ return v<x.v; } }d[N]; inline void addedge(int u,int v,int w){ e[++xb]=(edge){v,h[u],w}; h[u]=xb; e[++xb]=(edge){u,h[v],w}; h[v]=xb; } void dfs(int x,int fa){ f[x]=sz[x]=1; for(int i=h[x];i;i=e[i].next) if(e[i].to!=fa && !b[e[i].to])dfs(e[i].to,x),sz[x]+=sz[e[i].to],up(f[x],sz[e[i].to]); up(f[x],sum-sz[x]); if(f[rt]>f[x])rt=x; } void getdep(int x,int fa,int dep){ if(dep>dd)dd=dep; if(len[x]>a[z+dep])a[z+dep]=len[x]; for(int i=h[x];i;i=e[i].next) if(e[i].to!=fa && !b[e[i].to])len[e[i].to]=len[x]+e[i].c,getdep(e[i].to,x,dep+1); } bool work(int x){ int i,j; for(i=0;i<=sum;++i)m[i]=-(1ll<<50),a[i]=-(1ll<<50); w=z=0; for(i=h[x];i;i=e[i].next) if(!b[e[i].to]){ len[e[i].to]=e[i].c; dd=0; getdep(e[i].to,x,1); d[++w].v=dd; d[w].l=z+1; d[w].r=z+=dd; for(j=d[w].l+L-1;j<=z;++j)if(a[j]>0)return 1; } sort(d+1,d+w+1); for(j=d[1].l;j<=d[1].r;++j)m[j-d[1].l+1]=a[j]; for(i=2;i<=w;++i){ tt=1; ww=0; for(j=min(d[i-1].r-d[i-1].l+1,U-1);j>=L-1;--j){ while(ww && m[j]>m[q[ww]])--ww; if(!ww || m[j]>m[q[ww]])q[++ww]=j; } for(j=d[i].l;j<=d[i].r;++j){ if(j-d[i].l+1+q[tt]>U)++tt; if(tt<=ww && m[q[tt]]+a[j]>0)return 1; while(tt<=ww && m[L-(j-d[i].l+1)-1]>m[q[ww]])--ww; if(tt>ww || m[L-(j-d[i].l+1)-1]>m[q[ww]])q[++ww]=L-(j-d[i].l+1)-1; } for(j=d[i].l;j<=d[i].r;++j)up(m[j-d[i].l+1],a[j]); } return 0; } bool solve(int x){ b[x]=1; for(int i=h[x];i;i=e[i].next)if(sz[e[i].to]>sz[x])sz[e[i].to]=sum-sz[x]; if(work(x))return 1; for(int i=h[x];i;i=e[i].next) if(!b[e[i].to]){ sum=sz[e[i].to]; rt=0; dfs(e[i].to,x); if(solve(rt))return 1; } return 0; }}t;inline int getint(){ int x=0; char c=getchar(); while(!isdigit(c))c=getchar(); for(;isdigit(c);c=getchar())x=x*10+c-48; return x;}int main(){ scanf("%d%d%d",&n,&L,&U); for(i=1;i<n;++i){ scanf("%d%d%d",&u,&v,&w); t.addedge(u,v,w); if(w>r)r=w; } t.f[0]=1<<30; l=0; while(r-l>eps){ m=(l+r)/2; memset(t.b,0,sizeof t.b); t.sum=n; for(i=1;i<=t.xb;++i)t.e[i].c=t.e[i].w-m; t.dfs(1,t.rt=0); if(t.solve(t.rt))l=m; else r=m; } printf("%.3f\n",l); return 0;}
阅读全文
0 0
- bzoj1758重建计划,树的点分治+单调队列(可能是常见套路?)
- 【BZOJ1758】重建计划,点分治+单调队列
- 【bzoj1758】[Wc2010]重建计划 二分答案+单调队列+点分治
- BZOJ1758 [Wc2010]重建计划(二分答案+点分治+单调队列)
- 【BZOJ1758】【Wc2010】重建计划 树的点分治 二分
- 树的点分治 bzoj1758【WC2010】重建计划
- 【BZOJ1758】【Wc2010】重建计划 分数规划+树分治单调队列check
- BZOJ1758【点分治】【二分】【单调队列】
- [BZOJ1758] [WC2010] 重建计划 - 树分治
- BZOJ 1758 Wc2010 重建计划 树的点分治+二分+单调队列
- wc2010 bzoj1758(点分治+二分+单调队列) TLE
- 【BZOJ】【P1758】【Wc2010】【重建计划】【题解】【点分治+二分+单调队列】
- bzoj 1758 [Wc2010]重建计划 01分数规划 点分治 单调队列
- BZOJ1758 [WC2010]重建计划
- bzoj1758 [Wc2010]重建计划
- Bzoj:1758:[Wc2010]重建计划:树的点分治
- bzoj 3219: 巡游 (点分治+单调队列+二分)
- HDU5696 区间的价值(分治/单调队列)
- extjs异步刷新技术Ext.Ajax.request
- CSS content换行技术实现字符animation loading效果
- 详解--欧几里德算法
- Rxjava+retrofit+okhttp源码分析
- hdu 3535 AreYouBusy(多条件分类01背包)
- bzoj1758重建计划,树的点分治+单调队列(可能是常见套路?)
- 第七章 优雅地断开套接字连接
- MySql 事务与锁
- QR Code二维码原理
- 关于多线程学习遇到的一些问题
- 在handler中使用SmartUpload上传组件失败
- cmake——效率高跨平台的makefile生成神器
- PC Lint 用法说明,文件的作用
- Spring Cloud 服务链路追踪 (zipkin)