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. Anagrams [LeetCode]

    Given an array of strings, return all groups of strings that are anagrams. Note: All inputs will be ...

  2. Java 集合系列 12 TreeMap

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  3. Struts2动态结果(${})and全局结果(global-results)

    动态结果 例:根据判定动态结果区分用户进行登录 1.先在TestAction类中进行判定赋值 public class TestAction extends ActionSupport { priva ...

  4. OLE填充EXCEL

    先把基本的FORM写好: 1.行列属性 FORM row_column USING p_r p_width p_type. CASE p_type. WHEN 'R'. "行高 = p_r ...

  5. linux在shell date获取时间的相关操作

    获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 将当前日期赋值给DATE变量DATE=$(date +%Y%m%d) 有时候我们需要使用今天之前或者往后的日期,这时可以使用 ...

  6. linux 安装 php

    1.  libxml2安装           tar -zxvf libxml2-2.6.26.tar.gz cd libxml2-2.6.26 ./configure  --prefix=/usr ...

  7. Junit4的简单使用

    junit4的简单使用 测试套件的使用 测试类1 package com.westward; import static org.junit.Assert.*; import org.junit.Te ...

  8. Windows下将程序打包为安装包(最为简易的方式)

    一.准备工作:先下载一个Inno Setup编译器,这里我用到的是5.3.3中文版的. 软件介绍: Inno Setup 是一个免费的安装制作软件,小巧.简便.精美是其最大特点,支持pascal脚本, ...

  9. (转载)重新对APK文件签名

    1.将证书(debug.keystore)复制到与需要重新签名的apk文件相同的目录下(如:复制到D:\Sign) 2.在cmd中切换到需要重新签名的apk文件的目录下 3.使用WinRAR打开要重新 ...

  10. @ResultMapping注解

    @RequestMapping注解1.url映射放在方法上:@RequestMapping("/itemsEdit")2.窄化url请求映射放在类上,定义根路径,url就变成根路径 ...