简单的题面

给定一棵以1为根的有根树,点可能是黑色或白色,操作如下。

1. 选定一个点x,将x的子树中所有到x的距离为奇数的点的颜色反转。
2. 选定一个点x,将点x的颜色反转。
3. 选定一个点x,询问所有黑点y(包括点x)与点x的lca(最近公共祖先)的和。

果然自己码一码收获挺大的....

首先考虑怎么回答3操作,不妨考虑枚举$lca$

如果$lca = x$,可以发现,在$x$子树内的答案都是$x$

否则,根节点到$x$形成了一条链,令其为$1 \to x_1 \to x_2 ...... \to x$

可以发现,$x_i$对答案的贡献为$(sz[x_i] -  sz[x_{i + 1}]) * x_i$

由于答案分布在一条链上,考虑使用轻重链剖分

考虑到2操作和1操作

用线段树动态的维护

$sz[i][2][2], col[i]$

分别表示

1.$i$节点子树中,深度为奇 / 偶数,颜色为 黑 / 白的节点数

2.$i$节点的颜色

以及

$sum[2][2]$表示区间内所有$g[i][2][2]$的和

其中$g[i][x][y] = sz[i][x][y] * i$

还有一大堆的细节,直接看代码吧,无法用言语来描述

$51nod \;rank1$,$hhh$

还是有$8kb$......应该还能短点的

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; extern inline char gc() {
static char RR[], *S = RR + , *T = RR + ;
if(S == T) fread(RR, , , stdin), S = RR;
return *S ++;
}
inline int read() {
int p = , w = ; char c = gc();
while(c > '' || c < '') { if(c == '-') w = -; c = gc(); }
while(c >= '' && c <= '') p = p * + c - '', c = gc();
return p * w;
} int wr[], rw;
char WR[], *I = WR;
#define pc(z) *I ++ = (z)
template <typename re>
inline void write(re x) {
if(!x) pc('');
if(x < ) pc('-'), x = -x;
while(x) wr[++ rw] = x % , x /= ;
while(rw) pc(wr[rw --] + ''); pc('\n');
} #define fe float
#define de double
#define le long double
#define ll long long
#define ui unsigned int
#define ri register int
#define ull unsigned long long
#define sid 200050
#define eid 400050 int n, m, cnp, did;
int dfn[sid], ord[sid], anc[sid], col[sid];
int cap[sid], node[eid], nxt[eid];
int sz[sid], dep[sid], pre[sid], fa[sid]; inline void adeg(int u, int v) {
nxt[++ cnp] = cap[u]; cap[u] = cnp; node[cnp] = v;
} #define cur node[i]
inline void dfs(int o) {
sz[o] = ;
for(int i = cap[o]; i; i = nxt[i])
if(cur != fa[o]) {
fa[cur] = o; dep[cur] = dep[o] + ;
dfs(cur); sz[o] += sz[cur];
if(sz[pre[o]] < sz[cur]) pre[o] = cur;
}
} inline void dfs(int o, int tp) {
anc[o] = tp; dfn[++ did] = o; ord[o] = did;
if(pre[o]) dfs(pre[o], tp); else return;
for(int i = cap[o]; i; i = nxt[i])
if(cur != fa[o] && cur != pre[o]) dfs(cur, cur);
} int f[sid][][], g[sid][][];
inline void dp(int o) {
f[o][dep[o] & ][col[o]] = ;
for(int i = cap[o]; i; i = nxt[i])
if(cur != fa[o]) {
dp(cur);
for(ri d = ; d <= ; d ++)
for(ri c = ; c <= ; c ++)
f[o][d][c] += f[cur][d][c];
}
for(ri d = ; d <= ; d ++)
for(ri c = ; c <= ; c ++)
g[o][d][c] = f[o][d][c] - f[pre[o]][d][c];
} struct Seg {
ll s[][];
int rev[], mas[][];
} t[sid * ]; #define ls (o << 1)
#define rs (o << 1 | 1) inline void update(int o) {
for(ri i = ; i <= ; i ++)
for(ri j = ; j <= ; j ++)
t[o].s[i][j] = t[ls].s[i][j] + t[rs].s[i][j];
} inline void build(int o, int l, int r) {
if(l == r) {
int x = dfn[l];
for(ri i = ; i <= ; i ++)
for(ri j = ; j <= ; j ++)
t[o].s[i][j] = 1ll * g[x][i][j] * x;
return;
}
int mid = (l + r) >> ;
build(ls, l, mid); build(rs, mid + , r);
update(o);
} inline void prev(int o, int d, int l, int r) {
if(l == r) {
int x = dfn[l];
if((dep[x] & ) == d) col[x] ^= ;
swap(f[x][d][], f[x][d][]);
}
swap(t[o].s[d][], t[o].s[d][]);
swap(t[o].mas[d][], t[o].mas[d][]);
t[o].rev[d] ^= ;
} inline void premas(int o, int d, int c, int v, int l, int r) {
if(l == r) {
int x = dfn[l];
f[x][d][c] -= v; f[x][d][c ^ ] += v;
}
t[o].mas[d][c] += v;
} inline void pushdown(int o, int l, int r) {
int mid = (l + r) >> ;
for(ri i = ; i <= ; i ++)
if(t[o].rev[i]) {
t[o].rev[i] = ;
prev(ls, i, l, mid);
prev(rs, i, mid + , r);
}
for(ri i = ; i <= ; i ++)
for(ri j = ; j <= ; j ++)
if(t[o].mas[i][j] != ) {
premas(ls, i, j, t[o].mas[i][j], l, mid);
premas(rs, i, j, t[o].mas[i][j], mid + , r);
t[o].mas[i][j] = ;
}
} inline void rev(int o, int l, int r, int ml, int mr, int d) {
if(ml > mr) return;
if(ml > r || mr < l) return;
if(ml <= l && mr >= r) { prev(o, d, l, r); return; }
int mid = (l + r) >> ;
pushdown(o, l, r);
rev(ls, l, mid, ml, mr, d);
rev(rs, mid + , r, ml, mr, d);
update(o);
} inline void mas(int o, int l, int r, int ml, int mr, int d, int c, int v) {
if(ml > mr) return;
if(ml > r || mr < l) return;
if(ml <= l && mr >= r) { premas(o, d, c, v, l, r); return; }
int mid = (l + r) >> ;
pushdown(o, l, r);
mas(ls, l, mid, ml, mr, d, c, v);
mas(rs, mid + , r, ml, mr, d, c, v);
update(o);
} inline void mis(int o, int l, int r, int p, int d, int c, int v) {
if(l == r) {
f[p][d][c ^ ] += v; f[p][d][c] -= v;
t[o].s[d][c ^ ] += 1ll * v * p; t[o].s[d][c] -= 1ll * v * p;
return;
}
int mid = (l + r) >> ;
pushdown(o, l, r);
if(ord[p] <= mid) mis(ls, l, mid, p, d, c, v);
else mis(rs, mid + , r, p, d, c, v);
update(o);
} inline int qc(int o, int l, int r, int v) {
if(l == r) return col[v];
int mid = (l + r) >> ;
pushdown(o, l, r);
if(ord[v] <= mid) return qc(ls, l, mid, v);
else return qc(rs, mid + , r, v);
} inline int dsz(int o, int l, int r, int v, int d) {
if(l == r) return f[v][d][] - f[v][d][];
int mid = (l + r) >> ;
pushdown(o, l, r);
if(ord[v] <= mid) return dsz(ls, l, mid, v, d);
else return dsz(rs, mid + , r, v, d);
} inline int qsz(int o, int l, int r, int v) {
if(l == r) return f[v][][] + f[v][][];
int mid = (l + r) >> ;
pushdown(o, l, r);
if(ord[v] <= mid) return qsz(ls, l, mid, v);
else return qsz(rs, mid + , r, v);
} inline ll qs(int o, int l, int r, int ml, int mr) {
if(ml > mr) return ;
if(ml > r || mr < l) return ;
if(ml <= l && mr >= r) return t[o].s[][] + t[o].s[][];
int mid = (l + r) >> ;
pushdown(o, l, r);
return qs(ls, l, mid, ml, mr) + qs(rs, mid + , r, ml, mr);
} inline void change(int x) {
int d = (dep[x] + ) & , ff = anc[x];
int der = dsz(, , n, x, d);
rev(, , n, ord[x], ord[x] + sz[x] - , d);
mas(, , n, ord[ff], ord[x] - , d, , der);
for(ri i = anc[fa[ff]], j = fa[ff]; j; j = fa[i], i = anc[j])
mis(, , n, j, d, , der), mas(, , n, ord[i], ord[j] - , d, , der);
} inline void put(int x) {
int ff = anc[x];
col[x] = qc(, , n, x);
int d = dep[x] & , c = col[x];
mis(, , n, x, d, c, );
mas(, , n, ord[ff], ord[x] - , d, c, );
for(ri i = anc[fa[ff]], j = fa[ff]; j; j = fa[i], i = anc[j])
mis(, , n, j, d, c, ), mas(, , n, ord[i], ord[j] - , d, c, );
col[x] ^= ;
} inline ll query(int x) {
ll ans = ;
int f = anc[x];
ans += 1ll * qsz(, , n, x) * x;
for(ri i = f, j = x, o = x; j; j = fa[i], o = i, i = anc[j]) {
if(j != o) ans += 1ll * (qsz(, , n, j) - qsz(, , n, o)) * j;
ans += qs(, , n, ord[i], ord[j] - );
}
return ans;
} int main() {
n = read(); m = read();
for(ri i = ; i <= n; i ++) col[i] = read();
for(ri i = ; i < n; i ++) {
int u = read(), v = read();
adeg(u, v); adeg(v, u);
}
dfs(); dfs(, );
dp(); build(, , n);
for(ri i = ; i <= m; i ++) {
int opt = read(), x = read();
if(opt == ) change(x);
if(opt == ) put(x);
if(opt == ) write(query(x));
}
fwrite(WR, , I - WR, stdout);
return ;
}

51nod1819 黑白树V2的更多相关文章

  1. 51nod 1819 黑白树V2(树链剖分)

    第一次写如此复杂的树链剖分, 感觉自己代码能力还是挺不错的,没有调试太久(2个小时) 最后代码量高达11K orz(大部分都是重复的线段树代码,以后可以考虑优化一下代码量) 题解: 首先就是要进行一次 ...

  2. 【BZOJ】3319: 黑白树

    http://www.lydsy.com/JudgeOnline/problem.php?id=3319 题意:给一棵n节点的树(n<=1e6),m个操作(m<=1e6),每次操作有两种: ...

  3. 【BZOJ】3319: 黑白树(并查集+特殊的技巧/-树链剖分+线段树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3319 以为是模板题就复习了下hld............................. 然后n ...

  4. uoj #139. 【UER #4】被删除的黑白树 dfs序 贪心

    #139. [UER #4]被删除的黑白树 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/139 Descript ...

  5. [BZOJ 3319] 黑白树

    3319: 黑白树 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 557  Solved: 194[Submit][Status][Discuss] ...

  6. CodeM美团点评编程大赛初赛B轮 黑白树【DFS深搜+暴力】

    [编程题] 黑白树 时间限制:1秒 空间限制:32768K 一棵n个点的有根树,1号点为根,相邻的两个节点之间的距离为1.树上每个节点i对应一个值k[i].每个点都有一个颜色,初始的时候所有点都是白色 ...

  7. 【BZOJ3319】黑白树 并查集

    [BZOJ3319]黑白树 Description 给定一棵树,边的颜色为黑或白,初始时全部为白色.维护两个操作:1.查询u到根路径上的第一条黑色边的标号.2.将u到v    路径上的所有边的颜色设为 ...

  8. 【UOJ139】【UER #4】被删除的黑白树(贪心)

    点此看题面 大致题意: 请你给一棵树黑白染色,使每一个叶结点到根节点的路径上黑节点个数相同. 贪心 显然,按照贪心的思想,我们要让叶结点到根节点的路径上黑节点的个数尽量大. 我们可以用\(Min_i\ ...

  9. bzoj3319: 黑白树

    Description 给定一棵树,边的颜色为黑或白,初始时全部为白色.维护两个操作:1.查询u到根路径上的第一条黑色边的标号.2.将u到v    路径上的所有边的颜色设为黑色.Notice:这棵树的 ...

随机推荐

  1. 【BZOJ】1251: 序列终结者

    [题意]给定含有n个0的的数列. 1.区间加值 2.区间翻转 3.区间求最大值 [算法]平衡树(fhq-treap) 需要特别注意的是: 1.使0点对全局无影响并全程保持(例如求max,t[0].mx ...

  2. c++树,知道前序和中序求后序遍历

    经常有面试题就是知道一棵树的前序遍历和中序遍历让你写出后序遍历,这个慢慢画是能画出来的,但是要很快的弄出来还是要懂原理. 首先说一下三种遍历:所谓的前序后序和中序都是遍历时遍历根节点的顺序.子树的话依 ...

  3. python初步学习-python文件操作

    文件 文件,在python中,他是一种类型的对象,类似前面已经学过的其他数据类型,包括文本的.图片的.音频的.视频的等等,还有不少没见过的扩展名的.事实上,在linux操作系统中,所有的东西都被保存到 ...

  4. Daily Report-1126

    今日: 上午主要是回顾了react,阅读官方文档的时候发现了list中key值设计的必要性. 看了部分react源码,发现有些吃力,在询问羽牧学长之后调整策略,从redux和mobx入手,先多熟悉用法 ...

  5. pycharm设置字体大小

    pycharm 是很好的一个IDE,在windows下,和macOS下,都能很好的运行.唯一缺点是启动慢. 默认字体太小,在mac下,需要瞪大24K氪金狗眼才能看清. 为了保护好眼睛,我们需要把字体调 ...

  6. Linux内核中的常用宏container_of其实很简单【转】

    转自:http://blog.csdn.net/npy_lp/article/details/7010752 开发平台:Ubuntu11.04 编 译器:gcc version 4.5.2 (Ubun ...

  7. Android设备相关配置

    http://source.android.com/devices/tech/storage/index.html Android supports devices with external sto ...

  8. 15个你不得不知道的Chrome dev tools的小技巧

    转载自:https://www.imooc.com/article/2559 谷歌浏览器如今是Web开发者们所使用的最流行的网页浏览器.伴随每六个星期一次的发布周期和不断扩大的强大的开发功能,Chro ...

  9. juery中监听input的变化事件

    $('#searchValue').bind('input propertychange', function() { searchFundList(); });

  10. PHP发送邮件:如何自定义reply-to头部以及附件

    虽然有现成的类库(如PEAR)可以很方便地实现附件添加和发送,但是对于一些小站点(服务器硬件.网站规模都不理想),安装PEAR可能会带来不必要的负担,降低WEB程序运行效率. 通过对邮件格式的认识,我 ...