题目链接

题意:

  给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作:

    1 u v:u到v路径(最短)上的边都取成相反的颜色

    2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一个节点在路径上)

    3 u v:查询u到v路径上有多少个黑色边

思路:

  对树进行树链剖分,分成重链和轻链,用两棵线段树W,L来维护。W维护树上在重链上的u和v之间的边的翻转情况(操作在线段树上的[pos[v],pos[u]]区间);L维护树上在重链上的u和v之间的相邻边的翻转情况。那么某一个点u与它父亲节点fa[u]的边的最终翻转情况为:W(pos[u], pos[u])(如果边是重链上的边),W(pos[u], pos[u])^L(pos[fa[u]], pos[fa[u]])(如果边是轻链)。对于1操作,只要简单的在W上维护就可以了。对于2操作,除了在L上操作,还要注意头和尾的特殊处理(因为对于重链内的点,不包括头尾,只在W上查询),也就是u的重链上的儿子son[u]以及u的链头p=belong[u]要在W上翻转一次,结合图可能更能理解。还有就是线段树的操作了。

另外:

  u可能没有son[u],默认为虚点0,那么在线段树上需要加上一句话:if (l == r) return ;

#include <bits/stdc++.h>

const int N = 1e5 + 5;

//线段树
#define lson l, mid, o << 1
#define rson mid + 1, r, o << 1 | 1
struct Seg_Tree {
int fp[N<<2], s[N<<2];
void flip(int l, int r, int o) {
s[o] = (r - l + 1) - s[o];
fp[o] ^= 1;
}
void push_up(int o) {
s[o] = s[o<<1] + s[o<<1|1];
}
void push_down(int l, int r, int o) {
if (fp[o]) {
int mid = l + r >> 1;
flip (lson);
flip (rson);
fp[o] = 0;
}
}
void build(int l, int r, int o) {
fp[o] = s[o] = 0;
if (l == r) {
return ;
}
int mid = l + r >> 1;
build (lson);
build (rson);
}
void updata(int ql, int qr, int l, int r, int o) {
if (ql <= l && r <= qr) {
flip (l, r, o);
return ;
}
if (l == r) return ; //!
push_down (l, r, o);
int mid = l + r >> 1;
if (ql <= mid) updata (ql, qr, lson);
if (qr > mid) updata (ql, qr, rson);
push_up (o);
}
int query(int ql, int qr, int l, int r, int o) {
if (ql <= l && r <= qr) {
return s[o];
}
push_down (l, r, o);
int mid = l + r >> 1, ret = 0;
if (ql <= mid) ret += query (ql, qr, lson);
if (qr > mid) ret += query (ql, qr, rson);
push_up (o);
return ret;
}
}W, L; std::vector<int> edge[N];
int sz[N], dep[N], son[N], fa[N];
int pos[N], belong[N];
int loc;
int n; int query(int u, int v) {
int p = belong[u], q = belong[v], ret = 0;
while (p != q) {
if (dep[p] < dep[q]) {
std::swap (p, q);
std::swap (u, v);
}
if (u != p) {
ret += W.query (pos[son[p]], pos[u], 1, n, 1);
}
ret += (W.query (pos[p], pos[p], 1, n, 1) ^ L.query (pos[fa[p]], pos[fa[p]], 1, n, 1));
u = fa[p];
p = belong[u];
} if (u == v) return ret; if (dep[u] < dep[v]) {
std::swap (u, v);
}
ret += W.query (pos[son[v]], pos[u], 1, n, 1);
return ret;
} void modify(int t, int u, int v) {
int p = belong[u], q = belong[v];
while (p != q) {
if (dep[p] < dep[q]) {
std::swap (p, q);
std::swap (u, v);
}
if (t == 1) {
W.updata (pos[p], pos[u], 1, n, 1);
} else {
L.updata (pos[p], pos[u], 1, n, 1);
W.updata (pos[son[u]], pos[son[u]], 1, n, 1);
W.updata (pos[p], pos[p], 1, n, 1);
}
u = fa[p];
p = belong[u];
} if (dep[u] < dep[v]) {
std::swap (u, v);
}
if (t == 1) {
if (u == v) return ;
W.updata (pos[son[v]], pos[u], 1, n, 1);
} else {
L.updata (pos[v], pos[u], 1, n, 1);
W.updata (pos[son[u]], pos[son[u]], 1, n, 1);
W.updata (pos[v], pos[v], 1, n, 1);
}
} //树链剖分
void DFS2(int u, int chain) {
pos[u] = ++loc;
belong[u] = chain;
if (son[u]) {
DFS2 (son[u], chain);
}
for (auto v: edge[u]) {
if (v == fa[u] || v == son[u]) continue;
DFS2 (v, v);
}
} void DFS1(int u, int pa) {
sz[u] = 1; dep[u] = dep[pa] + 1;
son[u] = 0; fa[u] = pa;
for (auto v: edge[u]) {
if (v == pa) continue;
DFS1 (v, u);
sz[u] += sz[v];
if (sz[son[u]] < sz[v]) son[u] = v;
}
} void prepare() {
sz[0] = dep[0] = fa[0] = 0;
DFS1 (1, 0);
loc = 0;
DFS2 (1, 1);
W.build (1, n, 1);
L.build (1, n, 1);
} void init_edge(int n) {
for (int i=1; i<=n; ++i) {
edge[i].clear ();
}
} int main() {
int T;
scanf ("%d", &T);
while (T--) {
scanf ("%d", &n); init_edge (n);
for (int i=1; i<n; ++i) {
int u, v;
scanf ("%d%d", &u, &v);
edge[u].push_back (v);
edge[v].push_back (u);
} prepare (); int q;
scanf ("%d", &q);
while (q--) {
int t, u, v;
scanf ("%d%d%d", &t, &u, &v);
if (t == 3) {
printf ("%d\n", query (u, v));
} else {
modify (t, u, v);
}
}
}
return 0;
}

  

树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)的更多相关文章

  1. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  2. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  3. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  4. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  5. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  6. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  7. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  8. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  9. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  10. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

随机推荐

  1. ubuntu 12.04 LTS 64位兼容运行32位程序

    安装完Goagent,运行的时候出现了问题,在网络上翻看一些关于ubuntu的文档时,突然记起自己安装的是64位版,而goagent应该是32位的,于是通过sudo apt-get install i ...

  2. Be careful about the upper limit of integer

    在面对整数时,要留心整数溢出的情况. 在探索一个数有多少个除数的程序中,原本我们只要累加自然数到大于根号N停止即可. 不过因为计算机的整数范围的限制,我们需要判断是否i*i<(i-1)*(i-1 ...

  3. MVC 5使用TempData(对象)跨视图传递数据

    在控制器写好TempData:然后在Index.cshtml写一个链接,为了是让用户点击这个链接,能链至PageA()这个Action至. @Html.ActionLink("Show to ...

  4. erlang 虚机crash

    现网服务,每次更新一个服务时,另外一个集群所有node 都跟着同时重启一遍,这么调皮,这是闹哪样啊.. 看系统日志:/var/log/messages Oct 30 15:19:41 localhos ...

  5. Docker知识-1

    [编者的话]本文用图文并茂的方式介绍了容器.镜像的区别和Docker每个命令后面的技术细节,能够很好的帮助读者深入理解Docker. 这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(co ...

  6. Python全栈开发【基础四】

    Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 迭代器 三元表达式 列表解析与生成器表达式 生成器 匿名函数 lamb ...

  7. pycharm2016 激活

    pycharm 2016 专业版 激活方式选第二种 code 43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibG ...

  8. Code::Blocks如何支持C++11特性

    为了给同事分享C++11标准,需要一个演示C++11的编程环境.VS2013太大,安装起来不太方便.由于电脑上之前有安装codeblock,于是升级MinGW.去MinGW官网http://www.m ...

  9. iOS9 中的On-Demand Resources,编辑中。。。

    最近要写一个包含许多Html内容的应用,就想能不能通过ios9的这个新特性,缩小一下app的体积,也看看这个新特性和最常使用的用服务器下载资源包有什么不同. 先看官方文档: http://www.co ...

  10. set和map的简单用法

    .set(集合)map(映射)都属于关联类容器 都支持查询一个元素是否存在并能够有效地获取元素. set集合的元素总是从小到大排列,set集合通过二分查找树实现.它具备以下两个特点: ①:独一无二的元 ...