洛谷

Codeforces


这是一个非正解,被正解暴踩,但它还是过了。


思路

首先很容易想到DP。

设\(dp_{x,i}\)表示\(x\)子树全部被覆盖,而且向上恰好延伸到\(dep=i\)的位置,的最小费用。

转移方程非常显然:每次把\(dp_x\)和\(dp_v\)合并时\(dp_{x,i}+=\min\{dp_v\},dp_{v,i}+=\min\{dp_x\}\),然后对应位置取\(\min\)即可。

显然这东西可以用线段树合并维护,就做完了。

然而这题卡空间,需要垃圾回收。

线段树合并记得启发式合并!

我一定是太久没写线段树合并了……

不过最后几组数据(多半是hack数据)把我hack掉了,我在输出时特判才过。也许是炸long long的锅,但空间不允许我开__int128。


代码

  1. #include<bits/stdc++.h>
  2. clock_t t=clock();
  3. namespace my_std{
  4. using namespace std;
  5. #define pil pair<int,ll>
  6. #define fir first
  7. #define sec second
  8. #define MP make_pair
  9. #define rep(i,x,y) for (int i=(x);i<=(y);i++)
  10. #define drep(i,x,y) for (int i=(x);i>=(y);i--)
  11. #define go(x) for (int i=head[x];i;i=edge[i].nxt)
  12. #define templ template<typename T>
  13. #define sz 303030
  14. typedef long long ll;
  15. typedef double db;
  16. mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  17. templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
  18. templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
  19. templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
  20. templ inline void read(T& t)
  21. {
  22. t=0;char f=0,ch=getchar();double d=0.1;
  23. while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
  24. while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
  25. if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
  26. t=(f?-t:t);
  27. }
  28. template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
  29. char sr[1<<21],z[20];int C=-1,Z=0;
  30. inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
  31. inline void print(register int x)
  32. {
  33. if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
  34. while(z[++Z]=x%10+48,x/=10);
  35. while(sr[++C]=z[Z],--Z);sr[++C]='\n';
  36. }
  37. void file()
  38. {
  39. #ifndef ONLINE_JUDGE
  40. freopen("a.txt","r",stdin);
  41. #endif
  42. }
  43. inline void chktime()
  44. {
  45. #ifndef ONLINE_JUDGE
  46. cout<<(clock()-t)/1000.0<<'\n';
  47. #endif
  48. }
  49. #ifdef mod
  50. ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
  51. ll inv(ll x){return ksm(x,mod-2);}
  52. #else
  53. ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
  54. #endif
  55. // inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
  56. }
  57. using namespace my_std;
  58. int n,m;
  59. struct hh{int t,nxt;}edge[sz<<1];
  60. int head[sz],ecnt;
  61. void make_edge(int f,int t)
  62. {
  63. edge[++ecnt]=(hh){t,head[f]};
  64. head[f]=ecnt;
  65. edge[++ecnt]=(hh){f,head[t]};
  66. head[t]=ecnt;
  67. }
  68. #define Tree (sz*20)
  69. ll tr[Tree],tag[Tree];
  70. int ls[Tree],rs[Tree],size[Tree],cnt;
  71. int bin[Tree],top;
  72. void del(int k){tr[k]=1e17;tag[k]=ls[k]=rs[k]=0;if (top<Tree-1) bin[++top]=k;}
  73. int newnode(){int k=(top?bin[top--]:++cnt);tr[k]=1e17;return k;}
  74. #define lson ls[k],l,mid
  75. #define rson rs[k],mid+1,r
  76. void Add(int k,ll w){if (!k) return;tr[k]+=w;tag[k]+=w;}
  77. void pushdown(int k){Add(ls[k],tag[k]);Add(rs[k],tag[k]);tag[k]=0;}
  78. void ins(int &k,int l,int r,int x,ll y)
  79. {
  80. if (!k) size[k=newnode()]=1;
  81. chkmin(tr[k],y);
  82. if (l==r) return;
  83. pushdown(k);
  84. int mid=(l+r)>>1;
  85. if (x<=mid) ins(lson,x,y);
  86. else ins(rson,x,y);
  87. size[k]=size[ls[k]]+size[rs[k]];
  88. }
  89. ll query(int k,int l,int r,int x,int y)
  90. {
  91. if (!k) return 1e17;
  92. if (x<=l&&r<=y) return tr[k];
  93. int mid=(l+r)>>1;ll ret=1e17;
  94. pushdown(k);
  95. if (x<=mid) chkmin(ret,query(lson,x,y));
  96. if (y>mid) chkmin(ret,query(rson,x,y));
  97. return ret;
  98. }
  99. int root[sz];
  100. void merge(int &k,int l,int r,int &k2)
  101. {
  102. if (!k2) return;
  103. if (!k) size[k=newnode()]=1;
  104. if (size[k]<size[k2]) swap(k,k2);
  105. chkmin(tr[k],tr[k2]);
  106. if (l==r) return del(k2);
  107. int mid=(l+r)>>1;
  108. pushdown(k);pushdown(k2);
  109. merge(lson,ls[k2]);
  110. merge(rson,rs[k2]);
  111. del(k2);
  112. size[k]=size[ls[k]]+size[rs[k]];
  113. }
  114. vector<pil>V[sz];
  115. int dep[sz];
  116. void dfs(int x,int fa)
  117. {
  118. dep[x]=dep[fa]+1;
  119. ins(root[x],1,n,dep[x],0);
  120. #define v edge[i].t
  121. go(x) if (v!=fa)
  122. {
  123. dfs(v,x);
  124. ll w1=query(root[x],1,n,1,dep[x]),w2=query(root[v],1,n,1,dep[x]);
  125. Add(root[x],w2);Add(root[v],w1);
  126. merge(root[x],1,n,root[v]);
  127. }
  128. #undef v
  129. ll w;
  130. for (auto v:V[x])
  131. w=query(root[x],1,n,1,dep[x]),ins(root[x],1,n,dep[v.fir],w+v.sec);
  132. }
  133. int main()
  134. {
  135. file();
  136. int x,y,z;
  137. read(n,m);
  138. rep(i,1,n-1) read(x,y),make_edge(x,y);
  139. rep(i,1,m) read(x,y,z),V[x].push_back(MP(y,z));
  140. dfs(1,0);
  141. ll ans=query(root[1],1,n,1,1);
  142. printf("%lld",ans>=1e16||ans<0?-1ll:ans);
  143. return 0;
  144. }

Codeforces 671D Roads in Yusland [树形DP,线段树合并]的更多相关文章

  1. 【洛谷5298】[PKUWC2018] Minimax(树形DP+线段树合并)

    点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...

  2. 【pkuwc2018】 【loj2537】 Minmax DP+线段树合并

    今年年初的时候参加了PKUWC,结果当时这一题想了快$2h$都没有想出来.... 哇我太菜啦.... 昨天突然去搜了下哪里有题,发现$loj$上有于是就去做了下. 结果第一题我5分钟就把所有细节都想好 ...

  3. [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)

    还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...

  4. Codeforces 666E Forensic Examination SAM or SA+线段树合并

    E. Forensic Examination http://codeforces.com/problemset/problem/666/E 题目大意:给模式串S以及m个特殊串,q个询问,询问S的子串 ...

  5. BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)

    BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...

  6. LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】

    LINK 思路 首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小 ...

  7. [PKUWC2018]Minimax [dp,线段树合并]

    好妙的一个题- 我们设 \(f_{i,j}\) 为 \(i\) 节点出现 \(j\) 的概率 设 \(l = ch[i][0] , r = ch[i][1]\) 即左儿子右儿子 设 \(m\) 为叶子 ...

  8. P6847-[CEOI2019]Magic Tree【dp,线段树合并】

    正题 题目链接:https://www.luogu.com.cn/problem/P6847 题目大意 \(n\)个点的一棵树上,每个时刻可以割掉一些边,一些节点上有果实表示如果在\(d_i\)时刻这 ...

  9. Codeforces 671D. Roads in Yusland(树形DP+线段树)

    调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果 ...

随机推荐

  1. Win10下Prolific USB-to-Serial Comm Port驱动提示不能使用

    选择从计算机的设备驱动程序列表中选取 选择第一个安装即可.

  2. 梯度下降算法对比(批量下降/随机下降/mini-batch)

    大规模机器学习: 线性回归的梯度下降算法:Batch gradient descent(每次更新使用全部的训练样本) 批量梯度下降算法(Batch gradient descent): 每计算一次梯度 ...

  3. CDH5.12安装检查Inspector failed on the following hosts...

    1 安装检查报错 2 原因是因为自己的文件没有全部同步过去 hadoop003文件下面缺少了cm文件夹的内容 3 cp过去 scp -r cm root@hadoop003:/var/www/html ...

  4. Luogu P4479 [BJWC2018]第k大斜率

    一道清真简单的好写的题 Luogu P4479 题意 求点集两两连出的直线中斜率第$ k$大的直线 $ Solution$ 二分答案,设$x_j \geq x_i$ 若点$ (x_i,y_i)$和点$ ...

  5. Leetcode#867. Transpose Matrix(转置矩阵)

    题目描述 给定一个矩阵 A, 返回 A 的转置矩阵. 矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引. 示例 1: 输入:[[1,2,3],[4,5,6],[7,8,9]] 输出:[[1 ...

  6. Python Tornado简介

    简介 Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本.这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过为了 ...

  7. 🍓 react,jroll滑动删除 🍓

    import React, { Component } from 'react'; import '../src/css/reset.css'; import '../src/css/delete.c ...

  8. Css - 利于搜索引擎收录的三个标签

    Css - 利于搜索引擎收录的三个标签 <head> <meta charset="utf-8" /> <title>京东(JD.COM)-正品 ...

  9. 2017-2018-2 20165237 实验二《Java面向对象程序设计》实验报告

    ##2017-2018-2 20165237 实验二<Java面向对象程序设计>实验报告 No.1 实验要求: 实验三 敏捷开发与XP实践 http://www.cnblogs.com/r ...

  10. 查看oracle 用户执行的sql语句历史记录

      select * from v$sqlarea t order by t.LAST_ACTIVE_TIME desc