解:首先有個套路是一條邊的權值是[兩端點顏色不同]。這個用樹剖直接維護,支援修改。
每次詢問建虛樹,查詢虛樹上每條邊的權值。然後樹形dp,用開店的方法,每個點鏈加鏈查。
1 #include 2ac**3#define forson(x, i) for(int i = e[x]; i; i = edge[i].nex)
45 typedef long
long
ll;6
const
int n = 100010;7
8struct
edge edge[n << 1], edge[n]; int
tp, tp;
1213
inte[n], top[n], fa[n], son[n], siz[n], d[n], pos[n], id[n], num, val[n], n, imp2[n];
14int sum[n << 2], lc[n << 2], rc[n << 2], tag[n << 2
];15
intimp[n], k, stk[n], top, rt, time, e[n], vis[n], use[n], deep[n];
16ll siz[n], ans[n], d[n];
1718 inline void add(int x, int
y) 25
26///
------------------- tree 1 -------------------------
2728
void dfs_1(int x, int f) 40}
41return;42
}4344void dfs_2(int x, int f)
54return;55
}5657///
------------------ seg 1 ----------------------
5859
#define ls (o << 1)
60#define rs (o << 1 | 1)
6162 inline void pushup(int
o) 68
69 inline void pushdown(int
o) 76
return;77
}7879#undef ls
80#undef rs
8182
void build(int l, int r, int
o) 88
int mid = (l + r) >> 1
;89 build(l, mid, o << 1
);90 build(mid + 1, r, o << 1 | 1
);91
pushup(o);
92return;93
}9495void change(int l, int r, int v, int l, int r, int
o) 101
int mid = (l + r) >> 1
;102
pushdown(o);
103if(l <= mid) change(l, r, v, l, mid, o << 1
);104
if(mid < r) change(l, r, v, mid + 1, r, o << 1 | 1
);105
pushup(o);
106return
;107
}108
109int ask(int p, int l, int r, int
o) 116
117int getsum(int l, int r, int l, int r, int
o) 121
pushdown(o);
122int mid = (l + r) >> 1
;123
if(r <= mid) return getsum(l, r, l, mid, o << 1
);124
if(mid < l) return getsum(l, r, mid + 1, r, o << 1 | 1
);125
return getsum(l, r, l, mid, o << 1) + getsum(l, r, mid + 1, r, o << 1 | 1) + (rc[o << 1] != lc[o << 1 | 1
]);126
}127
128 inline int lca(int x, int
y) 135
return d[x] < d[y] ?x : y;
136}
137138 inline int getlen(int x, int
z) 148 ans += (col != ask(pos[x], 1, n, 1
));149
//printf("%d != %d \n", col, ask(pos[x], 1, n, 1));
150 ans += getsum(pos[z], pos[x], 1, n, 1
);151
//printf("return ans = %d \n", ans);
152return
ans;
153}
154155 inline void change(int x, int y, int
v) 161
else
165}
166if(d[x]
167 change(pos[y], pos[x], v, 1, n, 1
);168
return
;169
}170
171///
------------------- tree 2 ----------------------
172173 inline void add(int x, int
y) 182
183 inline bool cmp(const
int &a, const
int &b)
186187 inline void work(int
x) 193
194 inline void
build_t()
207if(y !=stk[top])
211 stk[++top] =x;
212}
213while(top > 1
) 217 rt =stk[top];
218return
;219
}220
221void dfs_1(int x)
228return
;229
}230
231void dfs_2(int x)
235for(int i = e[x]; i; i =edge[i].nex)
242return
;243
}244
245 inline void
cal()
252253
intmain()
260for(int i = 1, x, y; i < n; i++)
264 dfs_1(1, 0
);265 dfs_2(1, 1
);266 build(1, n, 1
);267
268for(int i = 1, f, x, y, z; i <= q; i++)
274else
281cal();
282 ll sum = 0
;283
for(int i = 1; i <= k; i++)
287//
printf("sum = %lld \n", sum);
288for(int i = 1; i <= k; i++)
291 puts(""
);292
}293
}294
return0;
295 }
洛谷P4241 採摘毒瘤
傳送門 完了我連揹包都不會了 考慮暴力,先列舉最小的數是哪個,設大小為 d i 個數為 k i 所有比它小的數的總和是 sum 然後把所有比它小的全都裝進揹包,它以及比他大的做乙個多重揹包,那麼設 dp j 表示在剩下的這些數里取的總和為 j 時的方案數,那麼 ans sum dp j 上面的式子意...
洛谷P3177 樹上染色
題目 一道非常好的樹形dp。狀態 dp u n 為u的子樹選n個黑點所能得到的收益最大值。則最終的結果就是 dp root k root 可以為任何值,為了方便,使 root 1 然後考慮怎麼狀態轉移,狀態轉移一般要從方程和邊界入手,考慮用揹包的思想,得到方程 dp now j max dp now...
洛谷P3177 樹上染色
題意 給n,k,n個點的樹,k個點是黑色的,n k點是白色的 給n 1條u,v,w,收益值是黑點兩兩距離之和,和白點兩兩距離之和的總值 求最大的收益值 思路 因為是樹形的,所以想到了求dp,dp u i 求u為根的選有多少i個黑點的收益值,然後卡殼 翻了題解,發現dp u i 求得是以u為根的 i ...