题目链接

题意:

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

    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. hdu 4946 2014 Multi-University Training Contest 8

    Area of Mushroom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  2. java从基础知识(十)java多线程(上)

    线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点 ...

  3. 一些js

    //fixed块随滚动条滚动 window.onscroll=function(){ var scroll_left = $(window).scrollLeft(); $('#table_fixed ...

  4. 深入浅析JAVA注解

    注解,相信大家都会知道,像@requestMapping,@Resource,@Controller等等的一些注解,大家都用过,那么,他的工具类你用过吗?下面就和大家一起来分享一下注解工具类. 注解的 ...

  5. [原创]jquery+css3打造一款ajax分页插件

    最近公司的项目将好多分页改成了ajax的前台分页以前写的分页插件就不好用了,遂重写一个 支持IE6+,但没有动画效果如果没有硬需求,个人认为没必要多写js让动画在这些浏览器中实现css3的动画本来就是 ...

  6. 服务端调用dubbo的方式

    方式1.通过dubbo 方式2.通过spring applicationContext-dubbo.xml 注意引入提供方的接口jar包

  7. airflow 部署

    环境 : ubuntu 14.04 LTS python 2.7 script: 设置环境变量: export AIRFLOW_HOME=~/airflow 安装相关依赖包: sudo apt-get ...

  8. vue.js 使用小结

    2016年12月10日 17:18:42 星期六 情景: 主要介绍 v-for 循环时对变量的处理方法 主要以table标签为例 1. 为 tr 标签动态添加属性 <tr v-for=" ...

  9. C/C++: C++变量和基本类型

    1. 如何选择类型的准则 当明确知晓数值不可能为负的时候,应该选择无符号类型. 使用int执行整数运算的时候,在实际应用中,short常常显得太小而long一般和int有一样的尺寸,如果数值超过了in ...

  10. 数据库 之MySQL 简单教程

      So Easy系列之MySQL数据库教程 1.   数据库概述 1.1.  数据库概述 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,它产生于距今六十多年前,随着信息技术和 ...