1758: [Wc2010]重建计划(TLE)

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=1758

题解?

  首先说明这道题我没过。
  那为啥要写题解?
  因为我确实写的正解啊。
  不就是先二分答案,然后点分治,然后单调队列,还得按子树深度从小到大吗。
  然后我就T了啊。
  不就是扫把图吗,我本地也很快啊。
  加数据的,你过来我和你说个事:我去年买了个表
  这个题啊,亦可赛艇。这个加数据人啊,更可赛艇。
  算了算了,自己渣怪不了别人。

代码(没过)

//二分+点分治+单调队列 
#include 
#include 
#include 
#define maxn 100010
#define eps 1e-8
#define inf 1e100
#define ll long long
#define forp for(int p=head[pos];p;p=nex[p])if(to[p]^pre and !grey[to[p]])
using namespace std;
int N, head[maxn], to[maxn<<1], nex[maxn<<1], tot, list[maxn], deep[maxn], G,
    size[maxn], ndtot, L, R, q[maxn], tmp[maxn], maxdeep[maxn], zs[maxn], up, cnt,
    tab[maxn], tong[maxn];
ll sumG, t;
double w[maxn<<1], dist[maxn], mid, ans, temp[maxn];
bool grey[maxn], flag;
inline void adde(int a, int b, double v)
{to[++tot]=b;w[tot]=v;nex[tot]=head[a];head[a]=tot;}
inline int read(int x=0)
{
    char c=getchar();
    while(c<48 or c>57)c=getchar();
    while(c>=48 and c<=57)x=(x<<1)+(x<<3)+c-48, c=getchar();
    return x;
}
void init()
{
    int a, b, v, i;
    N=read(), L=read(), R=read();
    for(i=1;iread(), b=read(), v=read(), adde(a,b,v),adde(b,a,v),up=max(up,v);
}
int dfs(int pos, int pre)
{
    maxdeep[pos]=deep[pos];
    list[++*list]=pos;
    size[pos]=1;
    forp dist[to[p]]=dist[pos]+w[p], deep[to[p]]=deep[pos]+1,
         size[pos]+=dfs(to[p],pos), maxdeep[pos]=max(maxdeep[pos],maxdeep[to[p]]);
    return size[pos];
}
void findG(int pos, int pre, ll sum)
{
    if(sumpos, sumG=sum;
    forp findG(to[p],pos,sum+*size-(size[to[p]]<<1));
}
inline int zhuang(int *a)
{
    int i, lim=0;
    for(i=1;i<=*a;i++)lim=max(lim,deep[a[i]]);
    for(i=0;i<=lim;i++)tong[i]=0;dist[0]=-inf;
    for(i=1;i<=*a;i++)if(dist[a[i]]>dist[tong[deep[a[i]]]])tong[deep[a[i]]]=a[i];
    return lim;
}
inline bool gao()
{
    int a, b, l=1, r=1, x, i, p=1, lim=0;
    *q=0;
    lim=zhuang(tmp);
    for(i=lim,*tmp=0;i>=0;i--)if(tong[i])tmp[++*tmp]=tong[i];
    lim=zhuang(list);
    for(i=0,*list=0;i<=lim;i++)if(tong[i])list[++*list]=tong[i];
    for(i=1;i<=*list;i++)
    {
        a=max(0,L-deep[list[i]]), b=max(0,R-deep[list[i]]);
        while(deep[tmp[p]]>=a and p<=*tmp)
        {
            while(land dist[tmp[p]]>dist[q[r-1]])r--;
            q[r++]=tmp[p++];
        }
        while(land deep[q[l]]>b)l++;
        if(land dist[q[l]]+dist[list[i]]>-eps)return true;
    }
    for(i=1;i<=*list;i++)tmp[++*tmp]=list[i];
    return false;
}
inline bool cmp(int a, int b){return maxdeep[a]int pos)
{
    int i, j;
    double l, r;
    *list=0, deep[pos]=0, *size=dfs(pos,-1);
    for(sumG=0,i=1;i<=*list;i++)sumG+=deep[list[i]];
    findG(G=pos,-1,sumG);
    grey[G]=1;
    *list=0, dist[G]=0, deep[G]=0, dfs(G,-1);
    for(i=1;i<=*list;i++)temp[list[i]]=dist[list[i]];
    for(i=1;i<=*list;i++)if(temp[list[i]]>ans-eps)break;
    *zs=0;
    for(int p=head[G];p;p=nex[p])if(!grey[to[p]])zs[++*zs]=to[p];
    sort(zs+1,zs+*zs+1,cmp);
    for(l=ans,r=up;r-l>1e-4;)
    {
        mid=(l+r)/2.0;
        tmp[*tmp=1]=G;
        for(i=1;i<=*zs;i++)
        {
            *list=0, dfs(zs[i],G);
            for(j=1;j<=*tmp;j++)dist[tmp[j]]=temp[tmp[j]]-deep[tmp[j]]*mid;
            for(j=1;j<=*list;j++)dist[list[j]]=temp[list[j]]-deep[list[j]]*mid;
            if(gao()){l=mid;break;}
        }
        if(i>*zs)r=mid;
    }
    ans=max(ans,l);
    for(int p=head[G];p;p=nex[p])if(!grey[to[p]])solve(to[p]);
}
int main()
{
    init();
    int i;
    double l, r;
    solve(1);
    printf("%.3lf",ans);
    return 0;
}

你可能感兴趣的:(二分答案,#,点分治,单调队列)