bzoj 1758 [Wc2010]重建计划 01分数规划 点分治 单调队列

来源:互联网 发布:安卓模拟器优化 编辑:程序博客网 时间:2024/04/29 05:18

直接01分数规划,然后把树分治查找所有链,然后合并时就是查一个定长区间的最大值,宽搜离线下来然后单调队列搞就行了。

不过我想说这题卡常数。。。卡常数。。。常数。。数。。
不过好像三个月之前做就没有这事了。。。

树分治可以预处理快了两倍,01分数规划从二分改成迭代快了四倍+,然而bz上还是跑了20+s。。。

#include <bits/stdc++.h>using namespace std;#define N 110000const double inf=1e15;int n,L,R,tot;int head[N],nex[N<<1],to[N<<1],val[N<<1];int vis[N],f[N],size[N],root,rt,sum,mxd,top;int deep[N],fa[N],st[N],q[N];double now,sv[N],rec[N],ans;vector<int>sr[N];char getc(){    static const int LEN = 4096;    static char buf[LEN],*S=buf,*T=buf;    if(S == T)    {        T = (S=buf)+fread(buf,1,LEN,stdin);        if(S == T)return EOF;    }    return *S++;}int read(){    static char ch;    static int D;    while(!isdigit(ch=getc()));    for(D=ch-'0'; isdigit(ch=getc());)        D=(D<<3)+(D<<1)+(ch-'0');    return D;}void add(int x,int y,int z){    tot++;    nex[tot]=head[x];head[x]=tot;    to[tot]=y;val[tot]=z;}void init(){    ans=-inf;    memset(vis,0,sizeof(vis));}void dfs1(int x,int y){    size[x]=1;    for(int i=head[x];i;i=nex[i])        if(to[i]!=y&&!vis[to[i]])        {            dfs1(to[i],x);            size[x]+=size[to[i]];        }}void dfs2(int x,int y){    f[x]=0;    for(int i=head[x];i;i=nex[i])        if(to[i]!=y&&!vis[to[i]])        {            dfs2(to[i],x);            f[x]=max(f[x],size[to[i]]);        }    f[x]=max(f[x],sum-size[x]);    root=f[x]<f[root] ? x:root;}void get(int x,int v){    st[top=1]=x;sv[1]=v;    deep[1]=1;fa[1]=0;    for(int i=1,t;i<=top;i++)    {        for(int j=head[t=st[i]];j;j=nex[j])            if(!vis[to[j]]&&to[j]!=fa[i])            {                st[++top]=to[j];                deep[top]=deep[i]+1;                fa[top]=t;sv[top]=sv[i]+val[j];            }    }    int h=1,r=0,pos=mxd;    for(int i=1,j,t;i<=top;i=j)    {        double mx=-inf;t=deep[i];        for(j=i;deep[j]==t&&j<=top;j++)            mx=max(mx,sv[j]);        while(pos>=0&&pos>=L-t)        {            while(h<=r&&rec[q[r]]<rec[pos])r--;            q[++r]=pos;pos--;        }        while(h<=r&&q[h]>R-t)h++;        if(h<=r)ans=max(ans,(rec[q[h]]+q[h]*now+mx)/(t+q[h]));    }    for(int i=1;i<=top;i++)        rec[deep[i]]=max(rec[deep[i]],sv[i]-now*deep[i]);    mxd=max(mxd,deep[top]);}void cal(int x){    vis[x]=1;mxd=0;rec[0]=0;    for(int i=head[x];i;i=nex[i])        if(!vis[to[i]])            get(to[i],val[i]);    for(int i=0;i<=mxd;i++)rec[i]=-inf;    for(int i=0;i<sr[x].size();i++)        cal(sr[x][i]);}double check(){    init();    cal(rt);    return ans;}void pre(int x){    vis[x]=1;    for(int i=head[x];i;i=nex[i])    if(!vis[to[i]])    {        dfs1(to[i],x);        root=0;sum=size[to[i]];        dfs2(to[i],x);        sr[x].push_back(root);        pre(root);    }}int main(){    n=read();L=read();R=read();    for(int i=1,x,y,z;i<n;i++)    {        x=read();y=read();z=read();        add(x,y,z);add(y,x,z);    }    dfs1(1,0);    f[0]=n+1;root=0;sum=n;    dfs2(1,0);    rt=root;pre(root);    for(int i=0;i<=n;i++)rec[i]=-inf;    double l=0,r=1e6;now=0;    while(r-l>=5e-5)    {        l=now;        now=check();        r=now;    }    printf("%.3lf\n",l);    return 0;}
0 0
原创粉丝点击