您的位置:首页 > 其它

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

2017-04-25 16:55 190 查看

链接

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

题解?

  首先说明这道题我没过。

  那为啥要写题解?

  因为我确实写的正解啊。

  不就是先二分答案,然后点分治,然后单调队列,还得按子树深度从小到大吗。

  然后我就T了啊。

  不就是扫把图吗,我本地也很快啊。

  加数据的,你过来我和你说个事:我去年买了个表

  这个题啊,亦可赛艇。这个加数据人啊,更可赛艇。

  算了算了,自己渣怪不了别人。

代码(没过)

//二分+点分治+单调队列
#include <cstdio>
#include <algorithm>
#include <ctime>
#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;i<N;i++)
a=read(), 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(sum<sumG)G=pos, 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(l<r and dist[tmp[p]]>dist[q[r-1]])r--;
q[r++]=tmp[p++];
}
while(l<r and deep[q[l]]>b)l++;
if(l<r and 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]<maxdeep[b];}
inline void solve(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: