首页 > 代码库 > Noi2014 购票
Noi2014 购票
传送门
另一个传送门
这题劲啊……
其实这题题解应该都烂大街了,不过我还是想大概写一下……就当是留作以后复习用也好……
$t=0$的斜率优化很好搞。
到了$t=1$的情况时,每个点都有转移区间的限制,做法大致就有线段树维护凸壳和分治两种,线段树维护凸壳没写过+太麻烦不想写,所以分治好了。把序列等分成两半之后考虑用左半更新右半,显然可以把右半按转移区间左端点排序,然后倒着加左边的点并处理右边的询问即可,因为需要在凸壳上二分,因此复杂度为$O(n\log^2n)$。
对于$t=3$的情况,把序列上的分治换成树分治即可。如果用点分治的话,每次找到重心之后先递归重心以上的部分,再在连通块内暴力得出重心的$f$,然后用重心到连通块最上方节点组成凸壳并更新重心以下各节点,最后递归重心以下各子树即可。当然还是要把各子树的点按转移左端点排序并逆序加点维护,复杂度仍然$O(n\log^2n)$。
1 /************************************************************** 2 Problem: 3672 3 User: hzoier 4 Language: C++ 5 Result: Accepted 6 Time:9748 ms 7 Memory:17924 kb 8 ****************************************************************/ 9 #include<cstdio> 10 #include<cstring> 11 #include<algorithm> 12 #include<vector> 13 using namespace std; 14 const int maxn=200010; 15 const long double eps=1e-12; 16 void dfs(int); 17 void solve(int); 18 int getcenter(int); 19 int bfs(int); 20 int getpoint(long long); 21 long double getk(int,int); 22 bool cmp(int,int); 23 vector<int>G[maxn]; 24 int p[maxn],size[maxn],son[maxn],s[maxn],top,q[maxn],vis[maxn]={0},tim=0; 25 long long f[maxn],d[maxn],b[maxn],l[maxn]; 26 int n,a[maxn]; 27 int main(){ 28 memset(f,63,sizeof(f)); 29 scanf("%d%*d",&n); 30 for(int i=2;i<=n;i++){ 31 scanf("%d%lld%d%lld%lld",&p[i],&d[i],&a[i],&b[i],&l[i]); 32 G[p[i]].push_back(i); 33 d[i]+=d[p[i]]; 34 } 35 f[1]=0; 36 solve(1); 37 for(int i=2;i<=n;i++)printf("%lld\n",f[i]); 38 return 0; 39 } 40 void solve(int x){ 41 x=bfs(x); 42 vis[x]=++tim; 43 if(p[x]&&!vis[p[x]]){ 44 int u=x; 45 while(p[u]&&!vis[p[u]])u=p[u]; 46 solve(u); 47 for(u=p[x];u&&(!vis[u]||vis[u]>vis[x])&&d[u]>=d[x]-l[x];u=p[u])f[x]=min(f[x],f[u]+a[x]*(d[x]-d[u])+b[x]); 48 } 49 bfs(x); 50 sort(q+1,q+size[x],cmp); 51 int i=1; 52 while(i<size[x]&&d[x]<d[q[i]]-l[q[i]])i++; 53 s[top=1]=x; 54 for(x=p[x];i<size[q[0]];i++){ 55 while(x&&(!vis[x]||vis[x]>vis[q[0]])&&d[x]>=d[q[i]]-l[q[i]]){ 56 while(top>1&&getk(x,s[top])+eps>getk(s[top],s[top-1]))top--; 57 s[++top]=x; 58 x=p[x]; 59 } 60 int j=getpoint(a[q[i]]); 61 f[q[i]]=min(f[q[i]],f[j]+a[q[i]]*(d[q[i]]-d[j])+b[q[i]]); 62 } 63 x=q[0]; 64 for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]])solve(G[x][i]); 65 } 66 int bfs(int x){ 67 int head=0,tail=0; 68 q[tail++]=x; 69 while(head!=tail){ 70 x=q[head++]; 71 size[x]=1; 72 son[x]=0; 73 for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]])q[tail++]=G[x][i]; 74 } 75 for(int i=tail-1;i;i--){ 76 size[p[q[i]]]+=size[q[i]]; 77 if(size[q[i]]>size[son[p[q[i]]]])son[p[q[i]]]=q[i]; 78 } 79 x=q[0]; 80 int s=size[x]; 81 while(son[x]&&(size[son[x]]<<1)>s)x=son[x]; 82 return x; 83 } 84 int getpoint(long long k){ 85 if(top<=1)return s[top]; 86 int L=1,R=top-1; 87 while(L<=R){ 88 int M=(L+R)>>1; 89 if(getk(s[M],s[M+1])-eps<k)R=M-1; 90 else L=M+1; 91 } 92 return s[L]; 93 } 94 inline long double getk(int i,int j){return (long double)(f[i]-f[j])/(d[i]-d[j]);} 95 bool cmp(int x,int y){return d[x]-l[x]>d[y]-l[y];}
新技能:斜率优化上树get√
Noi2014 购票
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。