HDU 4897 Little Devil I(树链剖分)(2014 Multi-University Training Contest 4)
The devil likes to make thing in chaos. This kingdom’s road system is like simply a tree(connected graph without cycle). A road has a color of black or white. The devil often wants to make some change of this system.
In details, we call a path on the tree from a to b consists of vertices lie on the shortest simple path between a and b. And we say an edge is on the path if both its two endpoints is in the path, and an edge is adjacent to the path if exactly one endpoint of it is in the path.
Sometimes the devil will ask you to reverse every edge’s color on a path or adjacent to a path.
The king’s daughter, WJMZBMR, is also a cute loli, she is surprised by her father’s lolicon-like behavior. As she is concerned about the road-system’s status, sometimes she will ask you to tell there is how many black edge on a path.
Initially, every edges is white.
For each test case, the first line contains an integer n, which is the size of the tree. The vertices be indexed from 1.
On the next n-1 lines, each line contains two integers a,b, denoting there is an edge between a and b.
The next line contains an integer Q, denoting the number of the operations.
On the next Q lines, each line contains three integers t,a,b. t=1 means we reverse every edge’s color on path a to b. t=2 means we reverse every edge’s color adjacent to path a to b. t=3 means we query about the number of black edge on path a to b.
T<=5.
n,Q<=10^5.
Please use scanf,printf instead of cin,cout,because of huge input.
定位:中等题 LCT和树链剖分都可以做,简单起见就说说树链剖分,LCT类似。
首先注意到一条路径上是log n条重链和log n条轻边。
当我们给一个点的所有边上的邻居边打标记时,如果该点在重链上,会影响他的轻孩子们。(要特殊考虑链头和链尾之类的)。
那么我们可以给重链上的点打标记,表示这个点的轻孩子们被翻转了没。
那么一个轻边就可以直接询问出来。复杂度:O(n(logn)^2)。
这个官方题解不怎么详细,我说一下我的解法:
首先跟普通的树链剖分一样,先给每个结点编上一个编号,每条重链用一个线段树来维护(其实都放到同一个线段树中了,占用不同的位置)
现在用线段树维护3个值:sum代表这个区间的黑边总数,flip代表这个区间的边是否被翻转颜色,light代表这个区间是否被打上了翻转标记(后面再说这个是啥)
其中所有边的编号为其靠下方的结点的编号,也就是根的编号在边的维护中没有意义
其中light代表这个点作为操作②所影响的次数,即它的轻边(不考虑与父节点的边)被翻转次数的奇偶。
维护这些值,考虑重链上的重边,某条边是黑色当且仅当它在线段树中的flip是1(被翻转了奇数次)。而对于不在重链上的边,它是黑色当且仅当它在线段树中的flip(被翻转的次数奇偶性)和它的父亲被打上翻转标记的次数light的和是奇数(异或值为1)。
那么,对于操作①,在树链往上走的时候,把所有边都翻转一次即可,没有什么难度。
对于操作②,在树链往上走的时候,除了要给所有路径上的点打上翻转标记以外,还要:翻转重链上的孩纸边,因为它要翻转而不受翻转标记的影响;翻转重链的父边,它是轻边,会受到重链的父亲的翻转标记的影响,所以直接给翻转一次抵消这种影响。
对于操作③,在树链往上走的时候,统计重链上的黑边和sum,和不在重链上的黑边(上面有讲)。
然后这样就差写代码了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL; const int MAXV = ;
const int MAXE = MAXV << ;
const int MAXT = MAXV << ; int head[MAXV], ecnt;
int to[MAXE], next[MAXE];
int n, m, T;
//Graph
void initGraph() {
memset(head + , -, n * sizeof(int));
ecnt = ;
} void add_edge(int u, int v) {
to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; next[ecnt] = head[v]; head[v] = ecnt++;
}
//Segment Tree
#define ll (x << 1)
#define rr (ll | 1)
#define mid ((l + r) >> 1)
int sum[MAXT], flip[MAXT];
int light[MAXT];//轻边是否翻转 void initSegmentTree() {
memset(sum + , , * n * sizeof(int));
memset(flip + , , * n * sizeof(int));
memset(light + , , * n * sizeof(int));
} void pushdown(int x, int l, int r) {
if(flip[x]) {
flip[ll] ^= ;
sum[ll] = (mid - l + ) - sum[ll];
flip[rr] ^= ;
sum[rr] = (r - mid) - sum[rr];
flip[x] = ;
}
if(light[x]) {
light[ll] ^= ;
light[rr] ^= ;
light[x] = ;
}
} void maintain(int x) {
sum[x] = sum[ll] + sum[rr];
} void modifyFlip(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
flip[x] ^= ;
sum[x] = (r - l + ) - sum[x];
} else {
pushdown(x, l, r);
if(a <= mid) modifyFlip(ll, l, mid, a, b);
if(mid < b) modifyFlip(rr, mid + , r, a, b);
maintain(x);
}
} void modifyLight(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
light[x] ^= ;
} else {
pushdown(x, l, r);
if(a <= mid) modifyLight(ll, l, mid, a, b);
if(mid < b) modifyLight(rr, mid + , r, a, b);
}
} int queryFlip(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
return sum[x];
} else {
int res = ;
pushdown(x, l, r);
if(a <= mid) res += queryFlip(ll, l, mid, a, b);
if(mid < b) res += queryFlip(rr, mid + , r, a, b);
return res;
}
} int queryLight(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
return light[x];
} else {
int res = ;
pushdown(x, l, r);
if(a <= mid) res += queryLight(ll, l, mid, a, b);
if(mid < b) res += queryLight(rr, mid + , r, a, b);
return res;
}
}
//树链剖分
int fa[MAXV], size[MAXV], son[MAXV], top[MAXV], tid[MAXV], dep[MAXV];
int dfs_clock; void dfs_size(int u, int f, int depth) {
fa[u] = f; dep[u] = depth;
size[u] = ; son[u] = ;
int maxsize = ;
for(int p = head[u]; ~p; p = next[p]) {
int &v = to[p];
if(v == f) continue;
dfs_size(v, u, depth + );
size[u] += size[v];
if(size[v] > maxsize) {
son[u] = v;
maxsize = size[v];
}
}
} void dfs_heavy_edge(int u, int ancestor) {
tid[u] = ++dfs_clock; top[u] = ancestor;
if(son[u]) dfs_heavy_edge(son[u], ancestor);
for(int p = head[u]; ~p; p = next[p]) {
int &v = to[p];
if(v == fa[u] || v == son[u]) continue;
dfs_heavy_edge(v, v);
}
} void modifyFlip(int a, int b) {
while(top[a] != top[b]) {
if(dep[top[a]] < dep[top[b]]) swap(a, b);
modifyFlip(, , n, tid[top[a]], tid[a]);
a = fa[top[a]];
}
if(a != b) {
if(dep[a] < dep[b]) swap(a, b);
modifyFlip(, , n, tid[son[b]], tid[a]);
}
} void modifyLight(int a, int b) {
while(top[a] != top[b]) {
if(dep[top[a]] < dep[top[b]]) swap(a, b);
modifyLight(, , n, tid[top[a]], tid[a]);
if(son[a]) modifyFlip(, , n, tid[son[a]], tid[son[a]]);
modifyFlip(, , n, tid[top[a]], tid[top[a]]);
a = fa[top[a]];
}
if(dep[a] < dep[b]) swap(a, b);
modifyLight(, , n, tid[b], tid[a]);
if(fa[b]) modifyFlip(, , n, tid[b], tid[b]);
if(son[a]) modifyFlip(, , n, tid[son[a]], tid[son[a]]);
} int query(int a, int b) {
int res = ;
while(top[a] != top[b]) {
if(dep[top[a]] < dep[top[b]]) swap(a, b);
if(a != top[a]) res += queryFlip(, , n, tid[son[top[a]]], tid[a]);
res += queryFlip(, , n, tid[top[a]], tid[top[a]]) ^ queryLight(, , n, tid[fa[top[a]]], tid[fa[top[a]]]);
a = fa[top[a]];
}
if(a != b) {
if(dep[a] < dep[b]) swap(a, b);
res += queryFlip(, , n, tid[son[b]], tid[a]);
}
return res;
} void ask() {
int a, b;
while(cin>>a>>b && a + b) {
cout<<query(a, b)<<endl;
}
} int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
initGraph();
for(int i = , a, b; i < n; ++i) {
scanf("%d%d", &a, &b);
add_edge(a, b);
}
initSegmentTree();
dfs_clock = ;
dfs_size(, , );
dfs_heavy_edge(, );
scanf("%d", &m);
for(int i = , op, a, b; i < m; ++i) {
scanf("%d%d%d", &op, &a, &b);
if(op == ) modifyFlip(a, b);
if(op == ) modifyLight(a, b);
if(op == ) printf("%d\n", query(a, b));
//if(i == 1) ask();
}
}
}
HDU 4897 Little Devil I(树链剖分)(2014 Multi-University Training Contest 4)的更多相关文章
- hdu 4897 Little Devil I (树链剖分+线段树)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4897 题意: 给你一棵树,一开始每条边都是白色,有三种操作: 1.将 u - v路径上的边转换颜色 ...
- HDU 4897 Little Devil I 树链剖分+线段树
Little Devil I Problem Description There is an old country and the king fell in love with a devil. T ...
- Hdu 5274 Dylans loves tree (树链剖分模板)
Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...
- hdu_4897_Little Devil I(树链剖分)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4897 题意:有三种操作,1是在树上的两个节点之间的路径改变当前的颜色,2是改变树上有且只有一个端点在u ...
- HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树
HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...
- Hdu 3966 Aragorn's Story (树链剖分 + 线段树区间更新)
题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2 ...
- BZOJ3862Little Devil I——树链剖分+线段树
题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...
- HDU 3966 Aragorn's Story(树链剖分)(线段树区间修改)
Aragorn's Story Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- HDU 5452——Minimum Cut——————【树链剖分+差分前缀和】ACdream 1429——Diversion——————【树链剖分】
Minimum Cut Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 65535/102400 K (Java/Others)Tota ...
- HDU 5293 Train chain Problem - 树链剖分(树状数组) + 线段树+ 树型dp
传送门 题目大意: 一颗n个点的树,给出m条链,第i条链的权值是\(w_i\),可以选择若干条不相交的链,求最大权值和. 题目分析: 树型dp: dp[u][0]表示不经过u节点,其子树的最优值,dp ...
随机推荐
- html之内联元素与块状元素;
html之内联元素与块状元素 一.html之内联元素与块状元素 1.块状元素一般比较霸道,它排斥与其他元素位于同一行内.比如div,并且width与height对它起作用. 2.内联元素只能容纳文本或 ...
- 面向对象之struct
struct PointStruct { int pointx = 1; int pointy = 2; public PointStruct(int x, int y) { this.pointx ...
- javascript小实例,PC网页里的拖拽
几年前,我参与设计开发一个房产网的项目,我负责前端工作,由于项目经理要求比较高,参考了很多房产类网站比较优秀的功能,想把别人比较优秀的设计和想法集合到一起,那时的设计稿和功能实现,简直就是改了又改,今 ...
- IAdaptable和IAdaptableFactory(转)
先记在这里,回头研究下. 原文:http://blog.csdn.net/mini_snow/article/details/3877379 1. 简介和简单的实现 IAdapteable实际上在Ec ...
- JavasScript判断输入框不为空
<form name="form1" method="POST" action="add.php"> <table wid ...
- How to pass selected records from form to dilog in AX 2012
static void main(Args args) { FormDataSource formDataSource; ; if(args.record().TableId == tablenum( ...
- Failed to load PDF in chrome/Firefox/IE
笔者的公司搭建了一个Nexus服务器,用来管理我们自己的项目Release构件和Site文档. 今天的问题是当用户访问一个Site里的PDF文件的时候,报错说“detected that the ne ...
- 由单例模式学到:volatile关键字
MSDN上说: volatile 关键字指示一个字段可以由多个同时执行的线程修改. 声明为 volatile 的字段不受编译器优化的限制. 这样可以确保该字段在任何时间呈现的都是最新的值. volat ...
- java实现读取文件内容(不同类型)
在一些项目中大量的数据经常需要从文件中读取,例如xml文件,txt文件,csv文件 1.读取本地的xml文件,需要注意对应的路径 //读取xml文件,xmlFile为读取文件的路径 DocumentB ...
- PHP如何解决网站大流量与高并发的问题
首先,确认服务器硬件是否足够支持当前的流量. 普通的P4服务器一般最多能支持每天10万独立IP,如果访问量比这个还要大, 那么必须首先配置一台更高性能的专用服务器才能解决问题 ,否则怎么优化都不可能彻 ...