【LOJ】#2722. 「NOI2018」情报中心
题解
考场上想了60分,但是由于自己不知道在怎么zz,我连那个ai<bi都没看到,误以为出题人没给lca不相同的部分分,然后觉得lca不同的部分想出来了要是相出lca相同的不就肝过去了……最后剩下的想法就是……为啥没给lca不同的呢……是我想错了???
剩了一个小时写暴力好像当时已经精神失常了,算了不想说了
出了考场写了一下60分,细节真是多到让我吐了,我代码能力疯狂下降吗,写了60分就370行了 出题人大毒瘤啊
从头到尾说一下部分分
前20给枚举链求链交的\(n^2\)暴力
再15分,似乎可以线段树,但是我归到S1的部分了
再15分c=0,可以枚举一个公共lca,求两个最小的v值,可以线段树合并,在lca处删除
再15分,就是相交部分是一条链的,这个枚举树上的每个点作为公共lca,然后我们就发现是
两条链的价值-代价 - 链交部分的价值
而链交部分的价值,就是这这个点深度 - 两条链中较低点lca的深度
忽略到枚举的点是常数
就是val1 - dis[lca1] + val2 或者 val2 - dis[lca2] + val1中的最大值即可,如果选了深度较小lca会被更新
直接线段树合并维护就好
猫锟卡乱搞了,大家散了吧
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <ctime>
#include <map>
#include <set>
#define fi first
#define se second
#define pii pair<int,int>
//#define ivorysi
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 50005
using namespace std;
typedef long long int64;
typedef double db;
typedef unsigned int u32;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9' ) {
res = res * 10 - '0' + c;
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
struct node {
int to,next;int64 val;
}E[MAXN * 2];
struct qry_node {
int u,v,lca;int64 val;
}qry[MAXN * 2];
int M,N,sumE,head[MAXN],fa[MAXN],dep[MAXN],pos[MAXN],st[MAXN * 2][20],idx,len[MAXN * 2],cnt;
int64 dis[MAXN],ans;
bool all_zero,all_lca_1,all_lca_distinct;
bool has[MAXN];
void add(int u,int v,int64 c) {
E[++sumE].to = v;
E[sumE].next = head[u];
E[sumE].val = c;
head[u] = sumE;
}
int min_dep(int a,int b) {
return dep[a] < dep[b] ? a : b;
}
int max_dep(int a,int b) {
return dep[a] > dep[b] ? a : b;
}
int lca(int a,int b) {
a = pos[a];b = pos[b];
if(a > b) swap(a,b);
int l = len[b - a + 1];
return min_dep(st[a][l],st[b - (1 << l) + 1][l]);
}
int64 Dist(int a,int b) {
return dis[a] + dis[b] - 2 * dis[lca(a,b)];
}
void dfs(int u) {
dep[u] = dep[fa[u]] + 1;
st[++idx][0] = u;
pos[u] = idx;
for(int i = head[u] ;i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u]) {
fa[v] = u;
dis[v] = dis[u] + E[i].val;
dfs(v);
st[++idx][0] = u;
}
}
}
void Init() {
sumE = 0;idx = 0;ans = -1e18;
all_zero = 1;all_lca_1 = 1;all_lca_distinct = 1;
memset(has,0,sizeof(has));
for(int i = 1 ; i <= N ; ++i) head[i] = 0;
read(N);
int a,b;int64 c;
for(int i = 1 ; i < N ; ++i) {
read(a);read(b);read(c);
add(a,b,c);add(b,a,c);
if(c != 0) all_zero = 0;
}
dfs(1);
for(int j = 1 ; j <= 19 ; ++j) {
for(int i = 1 ; i <= idx ; ++i) {
if(i + (1 << j) - 1 > idx) break;
st[i][j] = min_dep(st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
}
}
read(M);
for(int i = 1 ; i <= M ; ++i) {
read(a);read(b);read(c);
qry[i].u = a;qry[i].v = b;qry[i].lca = lca(a,b);
qry[i].val = Dist(a,b) - c;
if(has[qry[i].lca]) all_lca_distinct = 0;
if(qry[i].lca != 1) all_lca_1 = 0;
has[qry[i].lca] = 1;
}
}
namespace task1 {
void Solve() {
for(int i = 1 ; i <= M ; ++i) {
for(int j = 1 ; j <= M ; ++j) {
if(i == j) continue;
if(dep[qry[i].lca] < dep[qry[j].lca]) continue;
int u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].u));
int v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].v));
if(u == v) {
u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].v));
v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].u));
}
if(u != v) {
ans = max(ans,qry[i].val + qry[j].val - Dist(u,v));
}
}
}
}
int check() {
for(int i = 1 ; i <= M ; ++i) {
for(int j = 1 ; j <= M ; ++j) {
if(i == j) continue;
if(dep[qry[i].lca] < dep[qry[j].lca]) continue;
int u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].u));
int v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].v));
if(u == v) {
u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].v));
v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].u));
}
if(u != v) {
if(ans == qry[i].val + qry[j].val - Dist(u,v)) {
out(i);space;out(j);enter;
}
}
}
}
}
};
namespace task2 {
struct tr_node {
int lc,rc;
int64 maxa,maxb;
}tr[MAXN * 40];
int Ncnt,rt[MAXN];
vector<int> st[MAXN],ed[MAXN];
bool cmp(qry_node a,qry_node b) {
return a.v < b.v;
}
void update(int u) {
int64 la,lb,ra,rb;
la = lb = ra = rb = -2e18;
if(tr[u].lc) {
la = tr[tr[u].lc].maxa;lb = tr[tr[u].lc].maxb;
}
if(tr[u].rc) {
ra = tr[tr[u].rc].maxa;rb = tr[tr[u].rc].maxb;
}
tr[u].maxa = max(la,ra);
tr[u].maxb = max(lb,rb);
}
int Merge(int u,int v,int64 val) {
if(!u) return v;
if(!v) return u;
pii t[2] = {mp(tr[u].lc,tr[v].rc),mp(tr[u].rc,tr[v].lc)};
for(int i = 0 ; i <= 1 ; ++i) {
int a = t[i].fi,b = t[i].se;
if(!a || !b) continue;
ans = max(tr[a].maxa + tr[b].maxb + val,ans);
ans = max(tr[a].maxb + tr[b].maxa + val,ans);
}
tr[u].lc = Merge(tr[u].lc,tr[v].lc,val);
tr[u].rc = Merge(tr[u].rc,tr[v].rc,val);
if(!tr[u].lc && !tr[u].rc) {
tr[u].maxa = max(tr[u].maxa,tr[v].maxa);
tr[u].maxb = max(tr[u].maxb,tr[v].maxb);
}
else update(u);
return u;
}
void Insert(int &u,int L,int R,int pos,int64 va,int64 vb,bool on,int64 val) {
if(!u) {
u = ++Ncnt;
tr[u].lc = tr[u].rc = 0;
tr[u].maxa = tr[u].maxb = -2e18;
}
if(L == R) {
if(on) {
tr[u].maxa = va;tr[u].maxb = vb;
}
else {
tr[u].maxa = max(tr[u].maxa,va);
tr[u].maxb = max(tr[u].maxb,vb);
}
return;
}
int mid = (L + R) >> 1;
if(pos <= mid) {
Insert(tr[u].lc,L,mid,pos,va,vb,on,val);
if(tr[u].rc) {
ans = max(va + tr[tr[u].rc].maxb + val,ans);
ans = max(vb + tr[tr[u].rc].maxa + val,ans);
}
}
else {
Insert(tr[u].rc,mid + 1,R,pos,va,vb,on,val);
if(tr[u].lc) {
ans = max(va + tr[tr[u].lc].maxb + val,ans);
ans = max(vb + tr[tr[u].lc].maxa + val,ans);
}
}
update(u);
}
void dfs(int u) {
int s = st[u].size();
int64 ma,mb;
for(int i = 0 ; i < s ; ++i) {
int id = st[u][i];
if(dep[qry[id].lca] < dep[u]) {
Insert(rt[u],1,N,dep[qry[id].lca],qry[id].val,qry[id].val + dis[qry[id].lca],0,-dis[u]);
}
}
int64 tmp = -1e18;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u]) {
dfs(v);
if(rt[v]) Insert(rt[v],1,N,dep[u],-2e18,-2e18,1,-dis[u]);
rt[u] = Merge(rt[u],rt[v],-dis[u]);
}
}
ans = max(ans,tmp);
if(dep[N] == N) {
int s = ed[u].size();
int64 v = 2e18;
for(int i = 0 ; i < s ; ++i) {
int id = ed[u][i];
if(qry[id].u == qry[id].v) continue;
ans = max(ans,qry[id].val - v);
int64 t = -qry[id].val + 2 * (dis[qry[id].v] - dis[qry[id].u]);
v = min(v,t);
}
}
}
void Solve() {
Ncnt = 0;
for(int i = 1 ; i <= N ; ++i) {
rt[i] = 0;st[i].clear();ed[i].clear();
}
for(int i = 1 ; i <= M ; ++i) {
if(qry[i].u > qry[i].v) swap(qry[i].u,qry[i].v);
}
sort(qry + 1,qry + M + 1,cmp);
for(int i = 1 ; i <= M ; ++i) {
st[qry[i].u].pb(i);
st[qry[i].v].pb(i);
ed[qry[i].lca].pb(i);
}
dfs(1);
}
};
namespace task3 {
vector<int> st[MAXN],ed[MAXN];
struct tr_node {
int lc,rc;
int64 v,s;
}tr[MAXN * 40];
int rt[MAXN],Ncnt;
void update(int u) {
int64 lv,rv;
lv = rv = -2e18;tr[u].s = -1e18;
if(tr[u].lc) {lv = tr[tr[u].lc].v;tr[u].s = max(tr[u].s,tr[tr[u].lc].s);}
if(tr[u].rc) {rv = tr[tr[u].rc].v;tr[u].s = max(tr[u].s,tr[tr[u].rc].s);}
tr[u].v = max(lv,rv);
tr[u].s = max(tr[u].s,lv + rv);
}
int Merge(int u,int v) {
if(!u) return v;
if(!v) return u;
tr[u].lc = Merge(tr[u].lc,tr[v].lc);
tr[u].rc = Merge(tr[u].rc,tr[v].rc);
if(tr[u].lc || tr[u].rc) update(u);
return u;
}
void Insert(int &u,int L,int R,int pos,int64 v) {
if(!u) {
u = ++Ncnt;
tr[u].lc = tr[u].rc = 0;tr[u].v = -2e18;
tr[u].s = -1e18;
}
if(L == R) {
tr[u].v = v;return;
}
int mid = (L + R) >> 1;
if(pos <= mid) Insert(tr[u].lc,L,mid,pos,v);
else Insert(tr[u].rc,mid + 1,R,pos,v);
update(u);
}
void dfs(int u) {
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u]) {
dfs(v);
rt[u] = Merge(rt[u],rt[v]);
}
}
int s = st[u].size();
for(int i = 0 ; i < s ; ++i) {
int id = st[u][i];
if(dep[qry[id].lca] < dep[u]) {
Insert(rt[u],1,M,id,qry[id].val);
}
}
s = ed[u].size();
for(int i = 0 ; i < s ; ++i) {
int id = ed[u][i];
Insert(rt[u],1,M,id,-2e18);
}
if(rt[u]) {
ans = max(ans,tr[rt[u]].s);
}
}
void Solve() {
Ncnt = 0;
for(int i = 1 ; i <= N ; ++i) {
st[i].clear();ed[i].clear();rt[i] = 0;
}
for(int i = 1 ; i <= M ; ++i) {
st[qry[i].u].pb(i);
st[qry[i].v].pb(i);
ed[qry[i].lca].pb(i);
}
dfs(1);
}
};
namespace task4 {
vector<int> st[MAXN];
pii C[MAXN];
int64 V[MAXN * 4];
int f[MAXN * 4],cnt;
int64 get_dist(int a,int b) {
return Dist(f[a],f[b]) + V[a] + V[b];
}
void Merge(pii &path,int p) {
if(!p) return;
if(!path.se) path.se = p;
else if(!path.fi) path.fi = p;
else {
int64 x1 = get_dist(p,path.fi),x2 = get_dist(p,path.se),x3 = get_dist(path.fi,path.se);
if(x1 >= max(x2,x3)) {
path = mp(p,path.fi);
}
else if(x2 > max(x1,x3)) {
path = mp(p,path.se);
}
}
}
void dfs(int u) {
int s = st[u].size();
C[u] = mp(0,0);
if(u != 1) {
for(int i = 0 ; i < s ; ++i) {
Merge(C[u],st[u][i]);
if(C[u].fi && C[u].se) {
ans = max(ans,get_dist(C[u].fi,C[u].se) / 2 - dis[u]);
}
}
}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u]) {
dfs(v);
int t1[2] = {C[u].fi,C[u].se};
int t2[2] = {C[v].fi,C[v].se};
if(u != 1) {
for(int j = 0 ; j <= 1 ; ++j) {
for(int k = 0 ; k <= 1 ; ++k) {
int s = t1[j],t = t2[k];
if(!s || !t) continue;
ans = max(ans,get_dist(s,t) / 2 - dis[u]);
}
}
}
Merge(C[u],C[v].fi);Merge(C[u],C[v].se);
}
}
}
void Solve() {
for(int i = 1 ; i <= N ; ++i) {
st[i].clear();
}
cnt = 0;
for(int i = 1 ; i <= M ; ++i) {
qry[i].val = -qry[i].val + Dist(qry[i].u,qry[i].v);
V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].u];
f[cnt] = qry[i].v;
st[qry[i].u].pb(cnt);
V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].v];
f[cnt] = qry[i].u;
st[qry[i].v].pb(cnt);
}
dfs(1);
}
};
namespace task5 {
vector<pii > st[MAXN];
map<int,pii > dp[MAXN];
int64 V[MAXN * 4];
int f[MAXN * 4],cnt;
int64 get_dist(int a,int b) {
return Dist(f[a],f[b]) + V[a] + V[b];
}
void Merge(pii &path,int p) {
if(!p) return;
if(!path.se) path.se = p;
else if(!path.fi) path.fi = p;
else {
int64 x1 = get_dist(p,path.fi),x2 = get_dist(p,path.se),x3 = get_dist(path.fi,path.se);
if(x1 >= max(x2,x3)) {
path = mp(p,path.fi);
}
else if(x2 > max(x1,x3)) {
path = mp(p,path.se);
}
}
}
void dfs(int u) {
int s = st[u].size();
for(int i = 0 ; i < s ; ++i) {
pii t = st[u][i];
if(!dp[u].count(t.se)) {
dp[u][t.se] = mp(0,0);
}
Merge(dp[u][t.se],t.fi);
if(dp[u][t.se].fi && dp[u][t.se].se) {
ans = max(ans,get_dist(dp[u][t.se].fi,dp[u][t.se].se) / 2 - dis[u] + dis[t.se]);
}
}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u]) {
dfs(v);
if(dp[v].size() > dp[u].size()) swap(dp[u],dp[v]);
map<int,pii >::iterator it = dp[v].begin();
while(it != dp[v].end()) {
if(u != it->fi && dp[u].count(it->fi)) {
int t1[2] = {dp[u][it->fi].fi,dp[u][it->fi].se};
int t2[2] = {dp[v][it->fi].fi,dp[v][it->fi].se};
for(int j = 0 ; j <= 1 ; ++j) {
for(int k = 0 ; k <= 1 ; ++k) {
int s = t1[j],t = t2[k];
if(!s || !t) continue;
ans = max(ans,get_dist(s,t) / 2 - dis[u] + dis[it->fi]);
}
}
Merge(dp[u][it->fi],it->se.fi);
Merge(dp[u][it->fi],it->se.se);
}
else {
dp[u][it->fi] = it->se;
}
++it;
}
dp[v].clear();
}
}
dp[u].erase(u);
}
void Solve() {
cnt = 0;
for(int i = 1 ; i <= N ; ++i) {
st[i].clear();dp[i].clear();
}
for(int i = 1 ; i <= M ; ++i) {
qry[i].val = -qry[i].val + Dist(qry[i].u,qry[i].v);
V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].u] - dis[qry[i].lca];
f[cnt] = qry[i].v;
if(qry[i].u != qry[i].lca) st[qry[i].u].pb(mp(cnt,qry[i].lca));
V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].v] - dis[qry[i].lca];
f[cnt] = qry[i].u;
if(qry[i].v != qry[i].lca) st[qry[i].v].pb(mp(cnt,qry[i].lca));
}
dfs(1);
}
};
int main() {
#ifdef ivorysi
freopen("center4.in","r",stdin);
#else
freopen("center.in","r",stdin);
freopen("center.out","w",stdout);
#endif
for(int i = 2 ; i <= 100000 ; ++i) len[i] = len[i / 2] + 1;
int T;
read(T);
cnt = 0;
while(T--) {
Init();
if(M <= 300) task1::Solve();
else if(all_lca_1) task4::Solve();
else if(dep[N] == N) task2::Solve();
else if(all_zero) task3::Solve();
else if(all_lca_distinct) task2::Solve();
else {
task2::Solve();
task5::Solve();
}
if(ans <= -1e18) puts("F");
else {out(ans);enter;}
}
return 0;
}
直接调用task2和task5可以通过,然鹅我分部分分写的话直接用……task2处理一条链上同时所有lca为1的路径似乎有问题?懒得debug了= =
12.8K写得我真的非常开心
再20分的话,就非常神仙了
有个性质是链并的两倍等于两条链长 + u1 u2距离 + v1 v2距离
这时候再沿用前面思路的话就非常鸽
我们拆个式子
枚举u1和u2的lca是r
然后答案就是
dis[u_1] + dis[u_2] - 2 * dis[r] + (1链长价值 - 代价) - (2链长价值 - 代价) + dist(v1,v2)
我们多个附加点p1连向v1,边权是链长价值-代价 + dis[u_1]
当遇到u_1 的时候,加进去p_1,就相当于对于一个形态固定的树,加进去一个点可使用,找两个点集中各一个点的一条最长链
因为只有增加操作,那么两个点集中的各一个端点必然是两个点集中各自最长链的端点
最后20分,只要做一遍S1,再记录一下lca做一下S2,数组启发式合并就行……
我代码写的好长
NOI考完,我想我知道
我大概是LN的绝望了
【LOJ】#2722. 「NOI2018」情报中心的更多相关文章
- LOJ2722 「NOI2018」情报中心
「NOI2018」情报中心 题目描述 C 国和D 国近年来战火纷飞. 最近,C 国成功地渗透进入了D 国的一个城市.这个城市可以抽象成一张有$n$ 个节点,节点之间由$n - 1$ 条双向的边连接的无 ...
- LOJ #2721. 「NOI2018」屠龙勇士(set + exgcd)
题意 LOJ #2721. 「NOI2018」屠龙勇士 题解 首先假设每条龙都可以打死,每次拿到的剑攻击力为 \(ATK\) . 这个需要支持每次插入一个数,查找比一个 \(\le\) 数最大的数(或 ...
- loj#2718. 「NOI2018」归程
题目链接 loj#2718. 「NOI2018」归程 题解 按照高度做克鲁斯卡尔重构树 那么对于询问倍增找到当前点能到达的高度最小可行点,该点的子树就是能到达的联通快,维护子树中到1节点的最短距离 s ...
- loj#2721. 「NOI2018」屠龙勇士
题目链接 loj#2721. 「NOI2018」屠龙勇士 题解 首先可以列出线性方程组 方程组转化为在模p意义下的同余方程 因为不保证pp 互素,考虑扩展中国剩余定理合并 方程组是带系数的,我们要做的 ...
- Loj #2719. 「NOI2018」冒泡排序
Loj #2719. 「NOI2018」冒泡排序 题目描述 最近,小 S 对冒泡排序产生了浓厚的兴趣.为了问题简单,小 S 只研究对 *\(1\) 到 \(n\) 的排列*的冒泡排序. 下面是对冒泡排 ...
- loj#2720. 「NOI2018」你的名字
链接大合集: loj uoj luogu bzoj 单纯地纪念一下写的第一份5K代码.../躺尸 因为ZJOI都不会所以只好写NOI的题了... 总之字符串题肯定一上来就拼个大字符串跑后缀数组啦! ( ...
- loj 2719 「NOI2018」冒泡排序 - 组合数学
题目传送门 传送门 题目大意 (相信大家都知道) 显然要考虑一个排列$p$合法的充要条件. 考虑这样一个构造$p$的过程.设排列$p^{-1}_{i}$满足$p_{p^{-1}_i} = i$. 初始 ...
- LOJ #2718. 「NOI2018」归程 Dijkstra+可持久化并查集
把 $Noi2018$ day1t1 想出来还是挺开心的,虽然是一道水题~ 预处理出来 1 号点到其它点的最短路,然后预处理边权从大到小排序后加入前 $i$ 个边的并查集. 这个并查集用可持久化线段树 ...
- LOJ 2721 「NOI2018」屠龙勇士——扩展中国剩余定理
题目:https://loj.ac/problem/2721 1.注意别一输入 p[ i ] 就 a[ i ] %= p[ i ] ,因为在 multiset 里找的时候还需要真实值. 2.注意用 m ...
随机推荐
- vue2.0实战记录
1. 初始化项目vue init webpack caseone cd caseonecnpm installcnpm install less less-loader -Dcnpm install ...
- IOS计算文字高度
1.计算文字长度 NSString* str = @"你好"; .f; NSStringDrawingOptions options = NSStringDrawingUsesLi ...
- poj 1182/codevs 1074 食物链
http://poj.org/problem?id=1182 http://codevs.cn/problem/1074/ 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A吃B ...
- Could not open input file: artisan
执行php artisan 命令,报错Could not open input file: artisan artisan 是 Laravel 项目下的指令文件,在Laravel 项目的根目录下可以看 ...
- [整理]VS2010中如何添加“依赖","库目录","包含目录"
VS2010中如何添加“依赖","库目录","包含目录" 1. 添加编译所需要(依赖)的 lib 文件[解决方案资源管理器]“项目->属性-&g ...
- linux查询进程 kill进程
查询进程 #ps aux #查看全部进程 #ps aux|grep firewall #查询与firewall相关的进程 kill进程一 kill进程pid为711进程: #pkill -9 711 ...
- bootstrap_bootstrap中日历范围选择插件daterangepicker的使用
1.引入脚本 <link rel="stylesheet" type="text/css" href="assets/css/bootstrap ...
- VUE和ES6资源收集
MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript https://developer.mozilla.org/en/docs/We ...
- 20155303 2016-2017-2 《Java程序设计》第三周学习总结
20155303 2016-2017-2 <Java程序设计>第三周学习总结 教材学习内容总结 第四章 学会如何查询Java API文件对于Java的学习很有帮助,可以了解到如何使用各种方 ...
- 【NOI题解】【bzoj题解】NOI2008 bzoj1063 道路设计
@ACMLCZH学长出的毒瘤题T3.再也不是“善良”的出题人了. 题意:bzoj. 题解: 经典的树形DP题目,屡见不鲜了,然而我还是没有写出来. 这一类的题目有很多,例如这里的C题. 主要套路是把对 ...