树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)
题意:
给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作:
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(小恶魔)的更多相关文章
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- 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 ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
随机推荐
- Ubuntu虚拟机中断后重启网络断接错误解决方案
因为该死的windows自动更新,所以vmplayer经常会被强制关闭. 但重新启动后,会发生不能连接到网络的情况显示: waiting for the network configuration…… ...
- 在Azure虚拟机上安装SQL server
Azure虽然向用户提供SQL paas服务,但是大多数用户还是习惯在用虚拟机自己搭建SQL server,这样的好处是便于后期最大化的扩展,所以鉴于这些情况,所以觉得有必要写这篇博客. 首先,我们要 ...
- Appcan——Box
Box架构 ub….. Box架构元素空间大小分配比例 ub-f……. Ub-f1,ub-f2,ub-f3……. Box架构元素垂直方向的位置排列 ub-ac,ub-ae… -webkit-box-a ...
- win10 系统亮度调节
win10系统发行后,许多用户尝试新的系统发现安装之后亮度无法调节,我也多次遇见此情况 故在此记录修改方式: 打开注册表 -> 搜索键值featuretestcontrol -> 修改键值 ...
- web.xml添加编码过滤器
解决前后台交互汉字乱码 在项目中的web.xml中添加如下代码: <filter> <filter-name>CharacterEncodingFilter</filte ...
- django test
django的单元测试 官方文档:https://docs.djangoproject.com/en/dev/topics/testing/ 相对于自己封装urllib/urllib2/request ...
- ORA-00257: archiver error. Connect internal only, until freed.
早上BA抄送客户的邮件过来,说系统用不了,应用系统报异常Unable to open connection to oracle,Microsoft Provider v2.0.50727.42,既然是 ...
- 判断一个字符串str不为空的方法
1.str == null; 2."".equals(str); 3.str.length 4.str.isEmpty(); 注意:length是属性,一般集合类对象拥有的属性,取 ...
- ajaxFileupload多文件上传
最近有个功能模块需要上传图片,为了和之前的伙伴们保持一致我也使用了ajaxFileupload, 但是源码只支持单文件上传,所以百般斟酌之下决定修改源码,废话不多说直接上代码 HTML上传代码段: & ...
- Date、Calender类及日期和字符串转换
Calendar是一个抽象类,抽象类java.util.Calendar 不可以通过new来获取一个实例,可以通过类方法getinstance()获取此类型的一个通用的对象 ①用法: Calendar ...