bzoj2500: 幸福的道路(树形dp+单调队列)
好题。。
先找出每个节点的树上最长路
由树形DP完成
节点x,设其最长路的子节点为y
对于y的最长路,有向上和向下两种情况:
down:y向子节点的最长路g[y][0]
up:x的次长路的g[x][1]+dis[x][y]
up:up[fa[x]]+dis[x][y]
dfs1找向下,即向子节点的最长路
dfs2找向上的最长路
最后最长路f[i]=max(up[x],g[x][0])
第二部分
找最长连续子序列,使得序列中abs(mx-mn)<=m
这次学习了用单调队列的做法
两个队列mx,mn
mx存单减的f[i]的i,mn单增
由于差值不大于m
每次找出front的最小值出队就行了
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<queue> 5 #define LL long long 6 using namespace std; 7 const int maxn = 1000010; 8 struct node{ 9 int to,next; 10 LL cost; 11 }e[maxn]; 12 int n,m,tot,x; 13 LL g[maxn][2],f[maxn],y,head[maxn]; 14 15 void insert(int u, int v, LL c){ 16 e[++tot].to=v; e[tot].next=head[u]; head[u]=tot; e[tot].cost=c; 17 } 18 19 #define v e[i].to 20 void dfs1(int u){ 21 for (int i=head[u]; i!=-1; i=e[i].next){ 22 dfs1(v); 23 if (g[u][0]<g[v][0]+e[i].cost){ 24 g[u][1]=max(g[u][1],g[u][0]); 25 g[u][0]=g[v][0]+e[i].cost; 26 }else g[u][1]=max(g[u][1],g[v][0]+e[i].cost); 27 } 28 } 29 void dfs2(int u){ 30 for (int i=head[u]; i!=-1; i=e[i].next){ 31 f[v]=f[u]+e[i].cost; 32 if (g[v][0]+e[i].cost==g[u][0]) f[v]=max(f[v],g[u][1]+e[i].cost); 33 else f[v]=max(f[v],g[u][0]+e[i].cost); 34 dfs2(v); 35 } 36 } 37 38 int main(){ 39 scanf("%d%d", &n, &m); 40 tot=1; memset(head,-1,sizeof(head)); 41 for (int i=2; i<=n; i++){ 42 int x; LL y; 43 scanf("%d%lld", &x, &y); 44 insert(x,i,y); 45 } 46 dfs1(1); 47 dfs2(1); 48 for (int i=1; i<=n; i++) f[i]=max(f[i],g[i][0]); 49 deque<int> mx,mn; 50 int st=1; 51 int ans=0; 52 for (int i=1; i<=n; i++){ 53 while (!mx.empty() && f[mx.back()]<=f[i]) mx.pop_back(); 54 while (!mn.empty() && f[mn.back()]>=f[i]) mn.pop_back(); 55 mx.push_back(i); mn.push_back(i); 56 while (f[mx.front()]-f[mn.front()]>m){ 57 if (mx.front()<mn.front()){ 58 st=mx.front()+1; 59 mx.pop_front(); 60 } 61 else{ 62 st=mn.front()+1; 63 mn.pop_front(); 64 } 65 } 66 ans=max(ans,i-st+1); 67 } 68 printf("%d\n", ans); 69 return 0; 70 }