【BZOJ1758】【Wc2010】重建计划 树的点分治 二分

来源:互联网 发布:淘宝微淘怎么匿名 编辑:程序博客网 时间:2024/05/20 11:46

感觉仿佛所有统计路径的题都可以把锅甩给点分治???

由于要求平均值最大,我们每二分一个答案ave,就去检查是否存在一条路径满足其新路径长度(d(u,v)-ave)的和大于等于0,并且路径的长度在[L,R]之间,检查的时候技巧很多,可以用单调栈来维护当前各深度边权最大值。

同时,要善于利用时间戳来避免一切memset。并且由于答案是三位小数,因此我们可以控制当r-l<=1e-4时跳出即可。

/**************************************************************     Problem: 1758     User: RicardoWang     Language: C++     Result: Accepted     Time:23284 ms     Memory:13488 kb ****************************************************************/  #include<cstdlib> #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; #define maxn 100005 #define oo 999999999 struct edge {     int to,d,next; bool ban; }e[maxn*2]; int n,edge_ct,head[maxn],sz[maxn],L,R; void add(int x,int y,int de) {     e[++edge_ct]=(edge){y,de,head[x],false}; head[x]=edge_ct;     return ; } void _read(int &x) {     char ch=getchar(); x=0;while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();}return ; } int MMD; void Init() {     _read(n);edge_ct=0;     _read(L); _read(R);     int x,y,z;MMD=-1;     for(int i=1;i<n;i++)     {         _read(x);_read(y); _read(z);MMD=max(MMD,z);          add(x,y,z); add(y,x,z);     }     return ; } int maxd; int maxl[maxn]; void Get_gc(int now,int fa,int size,int &gc) {     bool flag=1;int j;     sz[now]=1;maxl[now]=0;     for(int id=head[now];id;id=e[id].next)     {         if(e[id].ban || e[id].to==fa)continue;         j=e[id].to;Get_gc(j,now,size,gc);         if(sz[j]>(size>>1))flag=false;         sz[now]+=sz[j];         maxd=max(maxd,maxl[now]+maxl[j]+1);maxl[now]=max(maxl[now],maxl[j]+1);     }     if(size-sz[now]>(size>>1))flag=false;      if(flag)gc=now;     return ; } double ans=-oo; int _time,_MaxD; double dp[maxn],dp1[maxn]; int T[maxn]; void DFS(int now,int fa,int dep,double sum,double ave) {     _MaxD=max(_MaxD,dep);     sz[now]=1;     if(T[dep]<_time || (T[dep]==_time && dp1[dep]<sum))dp1[dep]=sum,T[dep]=_time;     for(int id=head[now];id;id=e[id].next)     {         if(e[id].to==fa || e[id].ban)continue;         DFS(e[id].to,now,dep+1,sum-ave+(double)e[id].d,ave);sz[now]+=sz[e[id].to];     }     return ; } int qu[maxn],front,rear; bool Calc(int now,double ave) {     for(int i=0;i<=R;i++)dp[i]=-oo,T[i]=0;     dp[0]=0;_time=0;     int w;;     for(int id=head[now];id;id=e[id].next)     {         if(e[id].ban)continue;         _time++;         _MaxD=0;         DFS(e[id].to,now,1,(double)e[id].d-ave,ave);         //w=min(R,_MaxD);         w=max(0,L-_MaxD);         front=rear=1;         for(int i=_MaxD;i;i--)         {             for(;w+i<=R;w++)             {                 while(rear>front && dp[w]>dp[qu[rear-1]])rear--;                 qu[rear++]=w;             }             while(rear>front && qu[front]+i<L)front++;             if(rear>front && dp[qu[front]]+dp1[i]>=0)return true;         }                   for(int j=1;j<=_MaxD && j<=R;j++)if(T[j]==_time)         {             dp[j]=max(dp[j],dp1[j]);         }     }     return false; } void Tree_Devide(int now,int size) {     int gc;     maxd=0;     Get_gc(now,0,size,gc);     if(maxd<L)return ;     double l=ans,r=MMD,mid;     while(r-l>1e-4)     {         mid=(l*9.0+r)/10.0;         if(Calc(gc,mid))         {             ans=mid; l=mid;         }         else        {             r=mid;         }     }     for(int id=head[gc];id;id=e[id].next)if(!e[id].ban)     {         e[id].ban=e[id+(id%2==0 ? -1:1)].ban=true;         Tree_Devide(e[id].to,sz[e[id].to]);     }     return ; }   void work() {     Tree_Devide(1,n);     printf("%.3lf\n",ans);     return; } int main() {     //freopen("in.txt","r",stdin);     Init();     work();     return 0; }


 

0 0
原创粉丝点击