bzoj3672 [Noi2014]购票

推一下式子发现就是普通的斜率优化,但是放到了树上,那么我们怎么做呢,树上有什么能保证复杂度的求路径的算法呢,点分治!

但是这是有根树,我们对于首先处理点分治后的重心以及与根相连的那个块,之后我们将块中剩余的点按照向上扩展的最大深度排序,深度由大到小插入凸包,注意这里添加的点一定是在块内的,否则复杂度就错了。之后我们再处理其他的块。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <vector>
  7 #define N 205000
  8 #define inf 0x7fffffffffffffff
  9 #define int long long
 10 using namespace std;
 11 int MAX(int a,int b){return a>b?a:b;}
 12 struct point{
 13     int x[2];
 14     point(){}
 15     point(int a,int b){x[0]=a,x[1]=b;}
 16 };
 17 vector <point> v;
 18 double slope(point a,point b)
 19     {return (double)(a.x[1]-b.x[1])/1.0/(a.x[0]-b.x[0]);}
 20 int fa[N],size[N],maxn[N],s[N],p[N],q[N],l[N];
 21 int f[N],dep[N];
 22 int root,sum,vis[N<<1],lk[N];
 23 int e=2,head[N];
 24 struct edge{
 25     int u,v,w,next;
 26 }ed[N<<1];
 27 void add(int u,int v,int w){
 28     ed[e].u=u;ed[e].v=v;ed[e].w=w;
 29     ed[e].next=head[u];head[u]=e++;
 30 }
 31 void insert(int x){
 32     int sz=v.size();
 33     point P=point(dep[x],f[x]);
 34     while(sz>1&&slope(v[sz-2],v[sz-1])<=slope(v[sz-1],P))sz--,v.pop_back();
 35     v.push_back(P);
 36 }
 37 int query(int x){
 38     int l=1,r=v.size()-1,mid,ans=0;
 39     point P=point(1,p[x]);
 40     while(l<=r){
 41         mid=(l+r)>>1;
 42         if(slope(v[mid],v[mid-1])>=p[x])ans=mid,l=mid+1;
 43         else r=mid-1;
 44     }
 45     return v[ans].x[1]+(dep[x]-v[ans].x[0])*p[x]+q[x];
 46 }
 47 void dfs(int x){
 48     for(int i=head[x];i;i=ed[i].next){
 49         int v=ed[i].v;
 50         if(v==fa[x])continue;
 51         dep[v]=dep[x]+ed[i].w;
 52         dfs(v);
 53     }
 54 }
 55 void getroot(int rt,int x){
 56     size[x]=1;maxn[x]=0;
 57     for(int i=head[x];i;i=ed[i].next){
 58         int v=ed[i].v;
 59         if(vis[i])continue;
 60         getroot(rt,v);
 61         size[x]+=size[v];
 62         maxn[x]=MAX(maxn[x],size[v]);
 63     }
 64     maxn[x]=MAX(maxn[x],sum-size[x]);
 65     if(maxn[x]<maxn[root]||(maxn[x]==maxn[root]&&dep[x]<dep[root]))/*puts("??"),*/root=x;
 66 }
 67 int a[N],tot;
 68 void dfs1(int x){
 69     a[++tot]=x;
 70     for(int i=head[x];i;i=ed[i].next){
 71         int v=ed[i].v;
 72         if(vis[i])continue;
 73         dfs1(v);
 74     }
 75 }
 76 bool cmp(int a,int b)
 77     {return dep[a]-l[a]>dep[b]-l[b];}
 78 void work(int rt,int x){
 79     if(sum==1)return ;
 80     for(int i=head[x];i;i=ed[i].next){
 81         int v=ed[i].v;
 82         vis[i]=1;
 83     }
 84     int all=sum,sx=size[x];
 85     if(fa[x]&&!vis[lk[x]]){
 86         sum=size[fa[x]]>sx?all-sx+1:size[fa[x]]+1;
 87         root=0;getroot(rt,rt);work(rt,root);
 88     }
 89     tot=0;
 90     for(int i=head[x];i;i=ed[i].next){
 91         int v=ed[i].v;
 92         dfs1(v);
 93     }
 94     sort(a+1,a+tot+1,cmp);
 95     v.clear();
 96     for(int i=1,j=x;i<=tot;i++){
 97         int now=a[i];
 98         for(;j!=fa[rt]&&dep[j]>=dep[now]-l[now];j=fa[j])insert(j);
 99         if(v.size())f[now]=min(f[now],query(now));
100     }
101     for(int i=head[x];i;i=ed[i].next){
102         int v=ed[i].v;
103         root=0;sum=size[v]>sx?all-sx:size[v];
104         getroot(v,v);work(v,root);
105     }
106 }
107 int n,opt;
108 signed main(){
109     memset(f,0x3f,sizeof f);
110     f[1]=0;
111     scanf("%lld%lld",&n,&opt);
112     for(int i=2;i<=n;i++){
113         scanf("%lld%lld%lld%lld%lld",&fa[i],&s[i],&p[i],&q[i],&l[i]);
114         add(fa[i],i,s[i]);lk[i]=e-1;
115     }
116     dfs(1);
117     root=0;sum=n;maxn[0]=n+1;
118     getroot(1,1);
119     work(1,root);
120     for(int i=2;i<=n;i++)printf("%lld\n",f[i]);
121     return 0;
122 }
View Code

 

posted @ 2018-02-22 18:47  Ren_Ivan  阅读(158)  评论(0编辑  收藏  举报