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. EasyUI DataGrid View

    http://www.jeasyui.com/easyui/datagrid-detailview.js 前提一定要引入:datagrid-detailview.js主要是三个属性和普通的datgag ...

  2. word-wrap word-break white-space 用法。

    一.word-wrap使用: 语法: word-wrap : normal | break-word 取值说明: 1.normal和break-word,其中normal为默认值,当其值为normal ...

  3. [工程备案]linux基本命令以及C和C++编程

    whereis 查看程序安装在了哪里 where 产看运行程序在哪里. libtool --mode=link  g++ test.cpp  -o test  libSegmentorForSim2T ...

  4. linux web php 安全相关设置

    1 隐藏apache 或者 nginx的版本号 2 隐藏php的版本号 3 php 程序做好基本的防注入 xss之类的攻击 4 禁用PHP一些危险的函数 比如 phpinfo.system之类的 5 ...

  5. Java:一个简单的Java应用程序

    /** * 这是文档注释 * @version  * @author  */ /* 这之间的内容也是注释 */ //这是行注释 public class FirstSample { public st ...

  6. NSDateFormatter 根据时间戳求出时间

    NSDateFormatter 根据时间戳求出时间 - (void)detailWithStyle:(NSString*)style time:(NSInteger)time { // NSStrin ...

  7. c++普通高精除单精

    //没有在网上测试 //手测几组无误 //如有错误,还望指出,不胜感激. #include<cstdio>#include<cstring>int a1[600],a2,a4[ ...

  8. JobTracker启动流程源码级分析

    org.apache.hadoop.mapred.JobTracker类是个独立的进程,有自己的main函数.JobTracker是在网络环境中提交及运行MR任务的核心位置. main方法主要代码有两 ...

  9. Deep Learning 初识

    实际生活中,人们为了解决一个问题,如对象的分类(对象可是是文档.图像等),首先必须做的事情是如何来表达一个对象,即必须抽取一些特征来表示一个对象,如文本的处理中,常常用词**来表示一个文档,或把文档表 ...

  10. SQL 插入日期时间 变量值

    --看看吧^^ CREATE TABLE #temp ( test datetime ) go --SQL: INSERT #temp SELECT 1.1 UNION ALL GO --SQL: I ...