BZOJ 3672 NOI2014 购票 树的分治 NOI2014全AC达成!!!!

来源:互联网 发布:数据传输线 编辑:程序博客网 时间:2024/05/17 23:23

警告 本篇文章作者大脑已成一团浆糊,为了保证文章的流畅性,请阅读者将脑子搅成纸浆后方可正常阅读

UPD:此题解已废,新题解戳这里

首先题目大意:

给定一棵以1为根的有根树,边有边权,每个点有三个参数:p,q,l

从该点可以走到它的祖宗节点处,前提是距离d不超过l且花销为pd+q

昨天时间不咋多,就没写。。。今天中午吃完饭开始写,结果一直写到五点半,一下午课都没去上,死定了0.0

这题如果不是数的话就是斜率优化 但是尼玛 这是棵树!

去网上搜了半天题解 写的基本都是树的分治 我还没写过0.0 就试着写了写

其实树的分治不难写 关键是那个该死的l。。。调了半天第三个点过不去,最后发现原来是这么挂的


问题就出在这种情况上,最优解不在凸包上,但是经过l的分割后l左侧的点无法选择,最优解就进入了凸包,这种情况没法维护。。。。

然后我回去重新看了下题解 尼玛 原来题解的意思是树分治+CDQ分治!我勒个去这代码复杂度明显不是我的单核小脑瓜能承受的0.0

最后我用暴力代替的CDQ,把l到得到的伪最优解之间的点一一枚举。。。然后惊奇地发现过了0.0 第四第五个点跑了2s多 还好没超时

最后贴代码0.0 写的有点惨 我慢 我慢!

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define M 200200using namespace std;typedef long long ll;struct abcd{int to,next;ll f;int mark;}table[M];int head[M],tot;void add(int x,int y,ll z){table[++tot].to=y;table[tot].f=z;table[tot].next=head[x];head[x]=tot;}int n,t,fa[M],siz[M],queue[M],mark[M],r,h,cnt;ll p[M],q[M],l[M],f[M],dis[M];typedef pair<ll,ll> point;double getslope(point p1,point p2){    if(p1.first==p2.first)        return 2147483647*(p2.second>p1.second?1:-1);    return (double)( p2.second-p1.second )/( p2.first-p1.first );}point ps[M];struct Convex_Hull{point points[M];    int num[M],top;    double slope[M];    void insert(point p,int pos)    {        double s=0;        ll ff=p.second + ( dis[20] - p.first ) * ::p[20] + q[20];if(top)        while(1)        {            s=getslope(points[top],p);            if(top==1)                break;            if( s<slope[top] )                top--;            else                break;        }        points[++top]=p;        slope[top]=s;        num[top]=pos;    }    int divide(ll d,double s)    {        int l,re;        l=lower_bound(points+1,points+top+1, make_pair(d,0ll) )-points;        if(l==top+1)        return -1;        re=lower_bound(slope+l+1,slope+top+1,s)-slope;        return re-1;    }}hull;void CDQ_Tree(int root,int size,int T){int i,x,cog;if(size==1)return ;r=h=0;queue[++r]=root;while(r^h){x=queue[++h];siz[x]=1;for(i=head[x];i;i=table[i].next)if(!table[i].mark)queue[++r]=table[i].to;}for(i=size;i;i--){x=queue[i];siz[fa[x]]+=siz[x];if( (siz[x]<<1) > size )mark[fa[x]]=cnt;if( mark[x]!=cnt && (siz[x]<<1) >= size )cog=x;}for(i=head[cog];i;i=table[i].next)if(!table[i].mark)table[i].mark=T;CDQ_Tree(root,size-siz[cog]+1,++cnt);for(i=head[cog];i;i=table[i].next)if(table[i].mark==T)table[i].mark=0;r=0;for(i=cog;i!=fa[root];i=fa[i])queue[++r]=i;hull.top=0;h=r;hull.num[0]=r+1;for(i=r;i;i--)x=queue[i],ps[i]=make_pair(dis[x],f[x]),hull.insert( ps[i] , i );for(i=head[cog];i;i=table[i].next)queue[++r]=table[i].to;while(r^h){x=queue[++h];int num=hull.divide( dis[x]-l[x] , (double)p[x] );if(num>=0)for(i=hull.num[num-1]-1;i>=hull.num[num];i--){point p1=ps[i];if(dis[x]-ps[i].first<=l[x])f[x]=min( f[x] , p1.second + ( dis[x] - p1.first ) * p[x] + q[x] );}for(i=head[x];i;i=table[i].next)if(!table[i].mark)queue[++r]=table[i].to;}for(i=head[cog];i;i=table[i].next)CDQ_Tree(table[i].to,siz[table[i].to],++cnt);}int main(){//freopen("ticket.in","r",stdin);//freopen("ticket.out","w",stdout);int i,x,y;ll dist;cin>>n>>t;for(i=2;i<=n;i++){scanf("%d%lld%lld%lld%lld",&fa[i],&dist,&p[i],&q[i],&l[i]);add(fa[i],i,dist);}queue[++r]=1;while(r^h){x=queue[++h];for(i=head[x];i;i=table[i].next)dis[table[i].to]=dis[x]+table[i].f,queue[++r]=table[i].to;}memset(f,0x3f,sizeof f);f[1]=0;CDQ_Tree(1,n,++cnt);for(i=2;i<=n;i++)printf("%lld\n",f[i]==4557430888798830399ll?0:f[i]);}


1 0