Problem Little Devil I (HDU4897)

题目大意

  给定一棵树,每条边的颜色为黑或白,起始时均为白。

  支持3种操作:

    操作1:将a->b的路径中的所有边的颜色翻转。

    操作2:将所有 有且仅有一个点在a->b的路径中 的边的颜色翻转。

    操作3:询问a->b的路径中的黑色边数量。

解题分析

  考虑操作1,只需正常的树链剖分+线段树维护即可。用线段树维护每条边,tag_1[i]表示该区间中的黑色边数量。

  考虑操作2,一个节点相邻的边只可能为重链和轻链,且重链的数目小于等于2。故对于重链每次直接修改。对于轻链,则需要再用一棵线段树来维护每个节点,tag_2[i]表示该点所连接的所有轻链是否需要被翻转。

  考虑操作3,一条路径中的重链的信息均已存至第一棵线段树中,直接查询即可。对于轻链,还取决于该边的两个端点是否进行过操作2,用tag_2异或一下即可。

eg:轻链a->b ,则该链的颜色为tag_1[a->b] ^ tag_2[a] ^ tag_2[b]

  简要做法:

    操作1:每次修改一条重链和重链上方的一条轻链,表示这些链的颜色被翻转。

    操作2:每次直接修改一条重链上下方的重链,每个节点记录是否翻转。

    操作3:重链直接查询,轻链异或求得。

  时间复杂度(Qlog2(n))

参考程序

  看起来不大舒服,还是应该写成模板的形式。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> #define V 100008
#define E 200008
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 int n,m,Q;
int a[V],size[V],dep[V],fa[V],top[V],w[V],son[V],rank[V];
int tag_1[V << ],tag_2[V << ],lazy_1[V << ],lazy_2[V << ]; /*-----------------邻接表---------------*/
struct line{
int u,v,nt;
}eg[E];
int lt[V],summ,cnt; void adt(int u,int v){
eg[++summ].u=u; eg[summ].v=v; eg[summ].nt=lt[u]; lt[u]=summ;
} void add(int u,int v){
adt(u,v); adt(v,u);
}
/*---------------------------------------*/
/*------------------线段树---------------*/
void pushup(int rt){
tag_1[rt]=tag_1[rt<<]+tag_1[rt<<|];
} void pushdown_1(int rt,int m){
if (lazy_1[rt]){
tag_1[rt<<]= (m-m/) - tag_1[rt<<]; // wrong 4
tag_1[rt<<|]= (m/) - tag_1[rt<<|];
lazy_1[rt<<]^=;
lazy_1[rt<<|]^=;
lazy_1[rt]=;
}
} void pushdown_2(int rt){
if (lazy_2[rt]){
tag_2[rt<<]^=;
tag_2[rt<<|]^=;
lazy_2[rt<<]^=;
lazy_2[rt<<|]^=;
lazy_2[rt]=;
}
} void build(int l,int r,int rt){
tag_1[rt]=tag_2[rt]=lazy_1[rt]=lazy_2[rt]=;
if (l==r) return;
int m=(l+r) >> ;
build(lson);
build(rson);
pushup(rt);
} void update_1(int L,int R,int l,int r,int rt){
if (L <= l && r <= R) {
tag_1[rt]=r-l+-tag_1[rt];
lazy_1[rt]^=;
return;
}
pushdown_1(rt,r-l+);
int m = (l + r) >> ;
if (L <= m) update_1(L,R,lson);
if (m < R) update_1(L,R,rson);
pushup(rt); } void update_2(int L,int R,int l,int r,int rt){
if (L <= l && r <= R) {
tag_2[rt]^=;
lazy_2[rt]^=;
return;
}
pushdown_2(rt);
int m = (l + r) >> ;
if (L <= m) update_2(L,R,lson);
if (m < R) update_2(L,R,rson);
} int query_1(int L,int R,int l,int r,int rt){
if (L <= l && r <= R) {
return tag_1[rt];
}
pushdown_1(rt,r - l + );
int m = (l + r) >> ;
int res = ;
if (L <= m) res += query_1(L,R,lson);
if (m < R) res += query_1(L,R,rson);
return res;
} int query_2(int x,int l,int r,int rt){
if (l==r){
return tag_2[rt];
}
pushdown_2(rt);
int m= ( l + r ) >> ;
if (x <= m) return query_2(x,lson);
if (m < x) return query_2(x,rson);
} /*---------------------------------------*/
/*----------------树链剖分---------------*/ void dfs1(int u){
size[u]=; son[u]=;
for (int i=lt[u];i;i=eg[i].nt){
int v=eg[i].v;
if (v!=fa[u]){
fa[v]=u;
dep[v]=dep[u]+;
dfs1(v);
size[u]+=size[v];
if (size[v]>size[son[u]]) son[u]=v;
}
}
} void dfs2(int u,int tp,int x){
top[u]=tp; w[u]=++cnt; rank[cnt]=u;
if (son[u]) dfs2(son[u],tp,);
for (int i=lt[u];i;i=eg[i].nt){
int v=eg[i].v;
if (v==son[u] || v==fa[u]) continue;
dfs2(v,v,);
}
} void init(){
memset(lt,,sizeof(lt));
summ=; cnt=;
scanf("%d",&n);
for (int i=;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
}
dep[]=; fa[]=;
dfs1();
dfs2(,,);
build(,n,);
}
/*---------------------------------------*/
void work_1(int x,int y){
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) std::swap(x,y);
update_1(w[top[x]],w[x],,n,);
x=fa[top[x]];
}
if (dep[x]>dep[y]) std::swap(x,y);
update_1(w[x]+,w[y],,n,); //wrong 2
} void work_2(int x,int y){
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) std::swap(x,y);
update_2(w[top[x]],w[x],,n,);
if (son[x]) update_1(w[son[x]],w[son[x]],,n,);
if (son[fa[top[x]]]==top[x]) update_1(w[top[x]],w[top[x]],,n,);
x=fa[top[x]];
}
if (dep[x]>dep[y]) std::swap(x,y);
update_2(w[x],w[y],,n,);
if (son[y]) update_1(w[son[y]],w[son[y]],,n,);
if (son[fa[x]]==x) update_1(w[x],w[x],,n,);
} void work_3(int x,int y){
int res=;
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) std::swap(x,y);
res+=query_1(w[top[x]]+,w[x],,n,); //wrong 3
res+=query_1(w[top[x]],w[top[x]],,n,) ^ query_2(w[top[x]],,n,) ^ query_2(w[fa[top[x]]],,n,);
x=fa[top[x]];
}
if (dep[x]>dep[y]) std::swap(x,y);;
res+=query_1(w[x]+,w[y],,n,);
printf("%d\n",res);
} int main(){
int T;
scanf("%d",&T);
while (T--){
init();
scanf("%d",&Q);
while (Q--){
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
if (x==) work_1(y,z);
if (x==) work_2(y,z);
if (x==) work_3(y,z);
}
}
}

HDU4897 (树链剖分+线段树)的更多相关文章

  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. 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 ...

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

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

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

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

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

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

随机推荐

  1. CSS3发光字动画

    ;} img{ width:200px; height:200px; border:2px solid #000} .back h5 { font-size: 4em; color: #f2050b; ...

  2. WCF练习小程序总结

    1.什么是WCF 严格的说,WCF就是专门用于服务定制.发布与运行以及消息传递和处理的一组专门类的集合,也就是所谓的“类库”.这些类通过一定方式被组织起来,共同协 作,并为开发者提供了一个统一的编程模 ...

  3. linux shell 单引号 双引号 反引号的区别

    一.单引号和双引号 首先, 单引号和双引号,都是为了解决中间有空格的问题. 因为空格在linux中时作为一个很典型的分隔符,比如 string1=this is a string,这样执行就会报错.为 ...

  4. TaskTracker启动过程源码级分析

    TaskTracker也是作为一个单独的JVM来运行的,其main函数就是TaskTracker的入口函数,当运行start-all.sh时,脚本就是通过SSH运行该函数来启动TaskTracker的 ...

  5. 【NOIP2015】提高组D1 解题报告

    P1978神奇的幻方 Accepted 描述 幻方是一种很神奇的 N ∗ N 矩阵:它由数字 1,2,3, … … , N ∗ N 构成,且每行.每列及两条对角线上的数字之和都相同. 当 N 为奇数时 ...

  6. 根据窗体自动调整控件及文本框记住上次填写内容Demo

    第一次写文章,组词难免没有不通之处... 最近常用到Winform根据窗体大小自动调整空间大小及字体.文本框记住上次填写内容待下次输入某一段时候自动跳出上次输入内容.于是就随便把两个问题放到同一个de ...

  7. lastPathComponent的功能

    下面是官方的说明: 源字符串   --->     结果字符串 “/tmp/scratch.tiff”   --->     “scratch.tiff” “/tmp/scratch”   ...

  8. IBM RSA 的语言设置

    右键 IBM Rational software Architect for websphere software 快捷方式 ----> 打开文件位置 在 eclipse.ini 文件中添加参数 ...

  9. Browser GetImage

    using Microsoft.Win32; using System; using System.ComponentModel; using System.Drawing; using System ...

  10. C#代码 利用MongoDB中Group聚合函数查询

    例子: public static void getUserRFM(DateTime beginTime, DateTime endTime)        {            MongoDat ...