[2018-9-4T2]探索黑暗dark
题目大意:有一棵树,第$i$个点的点权为$s_i(s_1>0)$。初始有每个点都是亮的。$m$次修改,每次改变一个点的亮暗,回答包含$1$的全亮的连通块中点权和最大的连通块的和的值。
题解:正解不怎么会(我只打了一遍代码),这里是$97$分代码(复杂度$O(n^2log_2n)$,暴力复杂度$O(n^2)$,但是就是$97$。。。)(其实我只是想记录一下我考试的时候写的东西而已,没有任何参考价值)
第一次看题目的时候,把题目理解成了“在$1$所在的连通块中选出一些数,使它们最大”。这不是树剖+线段树+小$DP$吗?
令$w_u=\sum\limits_{v\in u的子树}(s_i\times[s_i>0])$,这可以$O(n)$求出。每次修改一个点$u$,找到它的父亲中第一个暗的(记为$f$)(对于树剖出来的每一条链的时间复杂度是$O(\log_2n)$的),把$w_{[f,u)}$都加上/减去$w_u$值(对于每一条链的时间复杂度也是$O(\log_2n)$的),在输出$w_1$就行了,总复杂度$O(n\log_2^2n)$(挺正常的呀)。
于是我兴冲冲地打了个代码,样例$1$过了(毕竟小样例一般都很简单),我没注意到大样例,就去写$T1$了。
离考试结束还有$30min-$的时候,我回来看了一下$T2$,发现有大样例,于是测了一下,果不其然的挂了,发现题目好像理解错了$QAQ$,开始改。
发现这样的话,对于区间$[f,u)$,若修改后的$w_{i,i\in [f,u)}\leqslant0$,就不会对上面产生贡献,就要$break$掉,而且不一定每一个值都加上/减去了$w_u$(修改前和修改后的$w_i$符号不相等,向上的贡献就会变化),似乎很麻烦。
于是我就记录一下区间的最小值,来判断这个区间是否有会有变号或者不会对上方产生贡献的点的点,修改这个区间,更改一下修改的值,继续操作,直到左端点不亮或者修改前后都小于零
这样,每次修改区间就有$O(n)$个,对于每个区间复杂度$O(\log_2n)$,但是想到这种题目肯定是随机数据(反正一般想不到这比暴力还劣的做法,也就没人卡),限制点的个数一定很少(区间少),于是信仰一交,发现是过了(考试的时候少写一句话没调出来,考试后调的)。
卡点:1.修改区间时,下一个区间的右端点求错(应该是 fa[f] ,写成 fa[dfn[f]] )。
C++ Code:($97$分)
#include <cstdio>
#define maxn 100010
const long long inf = 0x7fffffffffffffff;
int n, m;
long long w[maxn], W[maxn], ANS;
int head[maxn], cnt;
struct Edge {
int to, nxt;
} e[maxn << 1];
void addE(int a, int b) {
e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
}
inline long long max(long long a, long long b) {return a > b ? a : b;}
inline long long min(long long a, long long b) {return a < b ? a : b;}
namespace ST {
long long tg[maxn << 2], mn[maxn << 2];
bool V[maxn << 2];
inline void update(int rt) {
mn[rt] = min(mn[rt << 1], mn[rt << 1 | 1]);
}
void build(int rt, int l, int r) {
V[rt] = true;
if (l == r) {
mn[rt] = w[l];
return ;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
update(rt);
}
inline void pushdown(int rt) {
long long &x = tg[rt];
tg[rt << 1] += x;
tg[rt << 1 | 1] += x;
mn[rt << 1] += x;
mn[rt << 1 | 1] += x;
x = 0;
}
int L, R;
long long num;
void Add(int rt, int l, int r) {
if (L <= l && R >= r) {
mn[rt] += num;
tg[rt] += num;
return ;
}
int mid = l + r >> 1;
if (tg[rt]) pushdown(rt);
if (L <= mid) Add(rt << 1, l, mid);
if (R > mid) Add(rt << 1 | 1, mid + 1, r);
update(rt);
}
void add(int ll, int rr, long long Num) {
L = ll;
R = rr;
num = Num;
Add(1, 1, n);
}
bool modify(int rt, int l, int r, int p) {
if (l == r) return V[rt] = !V[rt];
int mid = l + r >> 1;
bool ans;
if (p <= mid) ans = modify(rt << 1, l, mid, p);
else ans = modify(rt << 1 | 1, mid + 1, r, p);
V[rt] = V[rt << 1] && V[rt << 1 | 1];
return ans;
}
int p;
long long ask(int rt, int l, int r) {
if (l == r) return tg[rt] + w[p];
int mid = l + r >> 1;
if (tg[rt]) pushdown(rt);
if (p <= mid) return ask(rt << 1, l, mid);
else return ask(rt << 1 | 1, mid + 1, r);
}
long long ask(int P) {
p = P;
return ask(1, 1, n);
}
int ans;
bool Query(int rt, int l, int r) {
if (V[rt] && (min(mn[rt], mn[rt] + num) >= 0)) return false;
if (l == r) {
ANS = min(mn[rt] + num, mn[rt]);
if (!V[rt]) ANS = inf;
ans = l;
return true;
}
// if (L <= l && R >= r) return V[rt];
if (tg[rt]) pushdown(rt);
int mid = l + r >> 1;
if (R > mid) if (Query(rt << 1 | 1, mid + 1, r)) return true;
if (L <= mid) if (Query(rt << 1, l, mid)) return true;
return false;
}
int query(int ll, int rr, long long Num) {
L = ll, R = rr, num = Num;
if (Query(1, 1, n)) return ans;
else return ll - 1;
}
}
int dfn[maxn], idx, top[maxn], son[maxn];
int dep[maxn], fa[maxn], sz[maxn], ret[maxn];
void dfs1(int u) {
sz[u] = 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa[u]) {
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
sz[u] += sz[v];
if (!son[u] || sz[v] > sz[son[u]]) son[u] = v;
}
}
}
void dfs2(int u) {
dfn[u] = ++idx;
ret[idx] = u;
int v = son[u];
if (v) top[v] = top[u], dfs2(v);
for (int i = head[u]; i; i = e[i].nxt) {
v = e[i].to;
if (v != fa[u] && v != son[u]) {
top[v] = v;
dfs2(v);
}
}
}
void dfs(int rt) {
// W[rt] = max(0, w[rt]);
W[rt] = w[rt];
for (int i = head[rt]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa[rt]) {
dfs(v);
W[rt] = max(W[rt], W[rt] + W[v]);
}
}
}
void modify(int x) {
bool o = ST::modify(1, 1, n, dfn[x]);
long long op = ST::ask(dfn[x]);
if (op <= 0) return ;
op *= (o ? 1ll : -1ll);
// printf("op:%lld\n", op);
x = fa[x];
while (x) {
int tmp = ST::query(dfn[top[x]], dfn[x], op);
if (tmp != dfn[top[x]] - 1) {
ST::add(tmp, dfn[x], op);
if (ANS == inf) break;
if (op < 0) {
op = op - ANS;
if (op >= 0) break;
} else {
op = op + ANS;
if (op <= 0) break;
}
x = fa[ret[tmp]];
} else {
ST::add(tmp + 1, dfn[x], op);
x = fa[top[x]];
}
}
// puts("over");
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 2; i <= n; i++) {
int a;
scanf("%d", &a);
addE(a, i);
addE(i, a);
}
dep[top[1] = 1] = 1;
dfs1(1);
dfs2(1);
for (int i = 1; i <= n; i++) scanf("%lld", w + i);
// for (int i = 1; i <= n; i++) printf("%lld ", dfn[i]); puts("");
dfs(1);
for (int i = 1; i <= n; i++) w[dfn[i]] = W[i];
ST::build(1, 1, n);
while (m --> 0) {
int a;
scanf("%d", &a);
modify(a);
printf("%lld\n", ST::ask(dfn[1]));
// for (int i = 1; i <= n; i++) printf("%lld ", ST::ask(dfn[i])); puts("");
}
return 0;
}
卡点:无
C++ Code:($100$分)
#include <cstdio>
#define maxn 100010
const long long inf = 0x3f3f3f3f3f3f3f3f;
int n, m;
long long w[maxn], ANS, now[maxn], sum[maxn];;
bool vis[maxn];
int head[maxn], cnt;
struct Edge {
int to, nxt;
} e[maxn << 1];
void addE(int a, int b) {
e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
}
inline long long max(long long a, long long b) {return a > b ? a : b;}
inline long long min(long long a, long long b) {return a < b ? a : b;}
namespace ST {
struct node {
long long a, b;
node(long long _a = 0, long long _b = 0) {a = _a, b = _b;}
inline node operator + (const node &rhs) {
return (node) {max(a + rhs.a, -inf), max(b + rhs.a, rhs.b)};
}
inline long long mx() {return max(a, b);}
} V[maxn << 2];
inline void update(int rt) {
V[rt] = V[rt << 1 | 1] + V[rt << 1]; //因为右节点深度深,是右节点转移到左节点
}
int L, R, p;
node num;
void add(int rt, int l, int r) {
if (l == r) {
V[rt] = num;
return ;
}
int mid = l + r >> 1;
if (p > mid) add(rt << 1 | 1, mid + 1, r);
else add(rt << 1, l, mid);
update(rt);
}
void add(int pos, node Num) {
p = pos;
num = Num;
add(1, 1, n);
}
node ask(int rt, int l, int r) {
if (L <= l && R >= r) return V[rt];
int mid = l + r >> 1;
node ans;
// printf("%d %d %d\n", rt, l, r);
if (R > mid) ans = ask(rt << 1 | 1, mid + 1, r);
if (L <= mid) ans = ans + ask(rt << 1, l, mid);
return ans;
}
node ask(int ll, int rr) {
L = ll;
R = rr;
// printf("%d %d\n", L, R);
return ask(1, 1, n);
}
}
int dfn[maxn], idx, top[maxn], son[maxn], down[maxn];
int dep[maxn], fa[maxn], sz[maxn], ret[maxn];
void dfs1(int u) {
sz[u] = 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa[u]) {
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
sz[u] += sz[v];
if (!son[u] || sz[v] > sz[son[u]]) son[u] = v;
}
}
}
void dfs2(int u) {
dfn[u] = ++idx; down[u] = u;
int v = son[u];
if (v) top[v] = top[u], dfs2(v), down[u] = down[v];
for (int i = head[u]; i; i = e[i].nxt) {
v = e[i].to;
if (v != fa[u] && v != son[u]) {
top[v] = v;
dfs2(v);
}
}
}
void modify(int x) {
long long tmp6 = vis[x] ? -inf : w[x], op = tmp6 - now[x]; now[x] = tmp6;
vis[x] ^= 1;
// printf("op:%lld\n", op);
while (top[x] != 1) {
sum[x] += op;
long long tmp = ST::ask(dfn[top[x]], dfn[down[x]]).mx();
ST::add(dfn[x], ST::node(sum[x]));
tmp = ST::ask(dfn[top[x]], dfn[down[x]]).mx() - tmp;
op = tmp;
x =fa[top[x]];
}
sum[x] += op;
ST::add(dfn[x], ST::node(sum[x]));
// puts("over");
}
int main() {
// freopen("dark.in", "r", stdin);
// freopen("dark.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i = 2; i <= n; i++) {
int a;
scanf("%d", &a);
addE(a, i);
addE(i, a);
}
dep[top[1] = 1] = 1;
dfs1(1);
dfs2(1);
// for (int i = 1; i <= n; i++) printf("%lld ", dfn[i]); puts("");
// dfs(1);
for (int i = 1; i <= n; i++) {
scanf("%lld", w + i);
modify(i);
vis[i] = true;
}
while (m --> 0) {
int a;
scanf("%d", &a);
modify(a);
printf("%lld\n", ST::ask(dfn[1], dfn[down[1]]).mx());
// for (int i = 1; i <= n; i++) printf("%lld ", ST::ask(dfn[i])); puts("");
}
return 0;
}

浙公网安备 33010602011771号