最长的包含K个点的简单路径 java_SPOJ 1825 经过不超过K个黑点的树上最长路径 点分治...

本文介绍了一个使用Java解决SPOJ 1825问题的算法,该问题涉及找到经过不超过K个黑点的树上最长简单路径。文章详细阐述了如何利用点分治的方法,包括添加边、更新深度、获取根节点等步骤,最终求解最长路径。
摘要由CSDN通过智能技术生成

#include#include#include

using namespacestd;const int MAXN = 2e6 + 5;const int MAXM = 2e6 + 5;int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], ed = 1;int cost[MAXM << 1];const int INF = ~0u >> 1;

inlinevoid addedge(int u, int v, intc)

{

to[++ed] =v;

cost[ed]=c;

nxt[ed]=Head[u];

Head[u]=ed;

}

inlinevoid ADD(int u, int v, intc)

{

addedge(u, v, c);

addedge(v, u, c);

}

inlineconst intreadin()

{int r = 0, k = 1;char c =getchar();for (; c < '0' || c > '9'; c = getchar()) if (c == '-') {

k= -1;

}for (; c >= '0' && c <= '9'; c =getchar()) {

r= r * 10 + c - '0';

}return k *r;

}intn, k, kk, m, anser, cnt, maxdep, summaxdep;intsz[MAXN], f[MAXN], dep[MAXN], sumsz, root;boolvis[MAXN];intok[MAXN], blasz[MAXN];inth[MAXN], g[MAXN];structnode {intblaval;intid;

} o[MAXN];boolcmp(node a, node b)

{return a.blaval

}void getroot(int x, intfa)

{

sz[x]= 1;

f[x]= 0;for (int i = Head[x]; i; i =nxt[i]) {int v =to[i];if (v == fa ||vis[v]) {continue;

}

getroot(v, x);

sz[x]+=sz[v];

f[x]=max(f[x], sz[v]);

}

f[x]= max(f[x], sumsz -sz[x]);if (f[x]

root=x;

}

}void update(int x, int blanum, int deep, intfa)

{if (blanum >kk) {return;

}

h[blanum]=max(h[blanum], deep);for (int i = Head[x]; i; i =nxt[i]) {int v =to[i];if (vis[v] || v ==fa) {continue;

}

update(v, blanum+ ok[v], deep +cost[i], x);

}

}void getdeep(int x, intfa)

{

blasz[x]=ok[x];for (int i = Head[x]; i; i =nxt[i]) {int v =to[i];if (v == fa ||vis[v]) {continue;

}

getdeep(v, x);

blasz[x]+=blasz[v];

}

}void calc(int x, intd)

{

cnt= 0;for (int i = Head[x]; i; i =nxt[i]) {int v =to[i];if(vis[v]) {continue;

}

getdeep(v, x);

node now;

now.blaval=blasz[v];

now.id=i;

o[++cnt] =now;

}

}void solve(intx)

{

summaxdep= -1;

kk= k -ok[x];ints;

vis[x]= 1;

calc(x,0);

sort(o+ 1, o + cnt + 1, cmp);for (int i = 1; i <= cnt; i++) {

maxdep= -1;int depnow =o[i].blaval;int v =to[o[i].id];int c =cost[o[i].id];

s=min(depnow, kk);for (int j = 0; j <= s; j++) {

h[j]= -INF;

}

update(v, ok[v], c, x);if (i == 1) {for (int j = 0; j <= s; j++) {

g[j]=h[j];

}

}else{for (int j = 0; j <= s; j++) {int aim = kk -j;

aim=min(aim, summaxdep);if (h[j] != -INF && g[aim] != -INF) {

anser= max(anser, h[j] +g[aim]);

}

}for (int j = 0; j <= s; j++) {

g[j]=max(h[j], g[j]);

}

}

summaxdep=s;for (int j = 1; j <= summaxdep; j++) {

g[j]= max(g[j], g[j - 1]);

}

}

anser=max(anser, g[min(kk, summaxdep)]);int totsz =sumsz;for (int i = Head[x]; i; i =nxt[i]) {int v =to[i];if(vis[v]) {continue;

}

root= 0;

sumsz= sz[v] > sz[x] ? totsz -sz[x] : sz[v];

getroot(v,0);

solve(root);

}

}intmain()

{

cnt= anser = 0;

n= readin(), k = readin(), m =readin();for (int now, i = 1; i <= m; i++) {

now=readin();

ok[now]= 1;

}intu, v, c;for (int i = 1; i < n; i++) {

u= readin(), v = readin(), c =readin();

ADD(u, v, c);

}

root= 0, sumsz = f[0] =n;

getroot(1, 0);

solve(root);

printf("%d\n", anser);return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值