http://acm.hdu.edu.cn/showproblem.php?pid=4897

题意:
给你一棵树,边的颜色要么为白色,要么为黑色,初始每条边为白色,有三种操作

1、将u-v链上面的所有边的颜色翻转
2、将u-v链上面所有邻接的边翻转(边上只有一个点在链上面)
3、询问u->v上面有多少黑色的边

树链剖分,线段树维护4个信息:

按dfs序建立线段树后,如果线段树内节点的区间为[l,r],则此节点维护树上dfs序[l,r]内的父边的信息

父边指 点与父节点之间的边

sum0:节点的父边属于重链且颜色为白色 的边数

sum1:节点的父边属于重链且颜色为黑色 的边数

rev1:节点的父边颜色是否被操作1取反 (实际只会用到属于轻链的边)

rev2:节点的子树中,与节点直接相连的属于轻链边 是否被操作2取反

操作1:直接取反,交换sum0和sum1,维护标记rev1

细节:最后u和v(dep[u]<dep[v])汇集到一条重链的时候,最后一次操作不包括u,因为点代表的是父边的信息

操作2:一条链的相邻边,除了对链上的点维护rev2操作外,

链最顶端的点如果是其父节点的重儿子,需要修改它的rev1

路径上每条重链最底端的点,如果它有重儿子,需要修改它重儿子的rev1

因为标记rev2只维护轻链

操作3:重链直接查,轻链呢?

在树链剖分往上跳的时候,跳轻链一定是只跳一条边

假设这条边连接了节点u和v,dep[u]<dep[v]

如果rev2[u]^rev2[v]^rev1[v] 为 true,则这条边为黑色

clj的题就是好哇!!!

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> using namespace std; #define N 100001 int n; int front[N],nxt[N<<],to[N<<],tot; int siz[N],dep[N],fa[N];
int bl[N],son[N];
int id[N],dy[N],cnt; bool big[N]; int sum0[N<<],sum1[N<<];
bool rev1[N<<],rev2[N<<]; int ans; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} void add(int u,int v)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
} void dfs1(int x)
{
siz[x]=;
for(int i=front[x];i;i=nxt[i])
if(to[i]!=fa[x])
{
fa[to[i]]=x;
dep[to[i]]=dep[x]+;
dfs1(to[i]);
siz[x]+=siz[to[i]];
}
} void dfs2(int x,int top)
{
bl[x]=top;
id[x]=++cnt;
dy[cnt]=x;
int y=;
for(int i=front[x];i;i=nxt[i])
if(to[i]!=fa[x] && siz[to[i]]>siz[y]) y=to[i];
if(y)
{
son[x]=y;
big[y]=true;
dfs2(y,top);
}
else return;
for(int i=front[x];i;i=nxt[i])
if(to[i]!=fa[x] && to[i]!=y) dfs2(to[i],to[i]);
} void down1(int k)
{
rev1[k<<]^=;
swap(sum0[k<<],sum1[k<<]);
rev1[k<<|]^=;
swap(sum0[k<<|],sum1[k<<|]);
rev1[k]^=;
} void down2(int k)
{
rev2[k<<]^=;
rev2[k<<|]^=;
rev2[k]^=;
} void Reverse(int k,int l,int r,int opl,int opr,int ty)
{
if(l>=opl && r<=opr)
{
if(ty==)
{
swap(sum1[k],sum0[k]);
rev1[k]^=;
}
else rev2[k]^=;
return;
}
int mid=l+r>>;
if(rev1[k]) down1(k);
if(rev2[k]) down2(k);
if(opl<=mid) Reverse(k<<,l,mid,opl,opr,ty);
if(opr>mid) Reverse(k<<|,mid+,r,opl,opr,ty);
if(ty==)
{
sum1[k]=sum1[k<<]+sum1[k<<|];
sum0[k]=sum0[k<<]+sum0[k<<|];
}
} int get_lca(int u,int v)
{
while(bl[u]!=bl[v])
{
if(dep[bl[u]]<dep[bl[v]]) swap(u,v);
u=fa[bl[u]];
}
return dep[u]<dep[v] ? u : v;
} bool point_query(int k,int l,int r,int x,int ty)
{
if(l==r) return ty== ? rev1[k] : rev2[k];
if(rev1[k]) down1(k);
if(rev2[k]) down2(k);
int mid=l+r>>;
if(x<=mid) return point_query(k<<,l,mid,x,ty);
return point_query(k<<|,mid+,r,x,ty);
} void query(int k,int l,int r,int opl,int opr)
{
if(l>=opl && r<=opr)
{
ans+=sum1[k];
return;
}
if(rev1[k]) down1(k);
if(rev2[k]) down2(k);
int mid=l+r>>;
if(opl<=mid) query(k<<,l,mid,opl,opr);
if(opr>mid) query(k<<|,mid+,r,opl,opr);
} void solve(int ty,int u,int v)
{
if(ty==)
{
while(bl[u]!=bl[v])
{
if(dep[bl[u]]<dep[bl[v]]) swap(u,v);
Reverse(,,n,id[bl[u]],id[u],);
u=fa[bl[u]];
}
if(dep[u]>dep[v]) swap(u,v);
if(u!=v) Reverse(,,n,id[u]+,id[v],);
}
else if(ty==)
{
int lca=get_lca(u,v);
if(lca!=u && lca!=v)
{
if(big[lca]) Reverse(,,n,id[lca],id[lca],);
}
else
{
if(dep[u]>dep[v]) swap(u,v);
if(big[u]) Reverse(,,n,id[u],id[u],);
}
while(bl[u]!=bl[v])
{
if(dep[bl[u]]<dep[bl[v]]) swap(u,v);
if(son[u]) Reverse(,,n,id[son[u]],id[son[u]],);
Reverse(,,n,id[bl[u]],id[u],);
u=fa[bl[u]];
}
if(dep[u]>dep[v]) swap(u,v);
if(son[v]) Reverse(,,n,id[son[v]],id[son[v]],);
Reverse(,,n,id[u],id[v],);
}
else
{
ans=;
while(bl[u]!=bl[v])
{
if(dep[bl[u]]<dep[bl[v]]) swap(u,v);
query(,,n,id[bl[u]],id[u]);
ans+=point_query(,,n,id[bl[u]],)^point_query(,,n,id[fa[bl[u]]],)^point_query(,,n,id[bl[u]],);
u=fa[bl[u]];
}
if(dep[u]>dep[v]) swap(u,v);
if(u!=v) query(,,n,id[u]+,id[v]);
printf("%d\n",ans);
}
} void build(int k,int l,int r)
{
sum0[k]=sum1[k]=;
rev1[k]=rev2[k]=false;
if(l==r)
{
sum0[k]=big[dy[l]];
return;
}
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
sum0[k]=sum0[k<<]+sum0[k<<|];
} void clear()
{
tot=cnt=;
memset(front,,sizeof(front));
memset(son,,sizeof(son));
memset(big,false,sizeof(big));
} int main()
{
freopen("data.in","r",stdin);
freopen("my.out","w",stdout);
int T;
read(T);
int u,v;
int ty,m,lca;
while(T--)
{
clear();
read(n);
for(int i=;i<n;++i)
{
read(u); read(v);
add(u,v);
}
dfs1();
dfs2(,);
build(,,n);
read(m);
while(m--)
{
read(ty); read(u); read(v);
solve(ty,u,v);
}
}
return ;
}

Little Devil I

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1087    Accepted Submission(s):
378

Problem Description
There is an old country and the king fell in love with
a devil. The devil always asks the king to do some crazy things. Although the
king used to be wise and beloved by his people. Now he is just like a boy in
love and can’t refuse any request from the devil. Also, this devil is looking
like a very cute Loli.

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.

 
Input
The first line contains an integer T, denoting the
number of the test cases.
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.

 
Output
For each t=3 operation, output the answer in one
line.
 
Sample Input
1
10
2 1
3 1
4 1
5 1
6 5
7 4
8 3
9 5
10 6

10
2 1 6
1 3 8
3 8 10
2 3 4
2 10 8
2 4 10
1 7 6
2 7 3
2 1 4
2 10 10

 
Sample Output
3

Hint

reverse color means change from white to black or vice virsa.

 
Author
WJMZBMR

hdu 4857 Little Devil I的更多相关文章

  1. HDU 4857 拓扑排序 优先队列

    n个数,已经有大小关系,现给m个约束,规定a在b之前,剩下的数要尽可能往前移.输出序列 大小关系显然使用拓扑结构,关键在于n个数本身就有大小关系,那么考虑反向建图,优先选择值最大的入度为零的点,这样得 ...

  2. HDU 4857

    HDU 4857 (反向拓扑排序 + 优先队列) 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须 ...

  3. HDU 4857 topological_sort

    逃生 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission ...

  4. codeforce E - Minimal Labels+hdu 4857

    两个题目的意思差不多 都是希望得出的拓扑序如果有多种 要求输出字典序小的情况 这里引用一个大佬的博客 关于为什么不能直接建图然后用小根堆解决这个问题(http://blog.csdn.net/rgno ...

  5. HDU 4857 逃生 (反向拓扑排序 & 容器实现)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857 逃生 Time Limit: 2000/1000 MS (Java/Others)    Mem ...

  6. HDU 4857 逃生 (优先队列+反向拓扑)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857 解题报告:有n个点,有m个条件限制,限制是像这样的,输入a  b,表示a必须排在b的前面,如果不 ...

  7. HDU 4897 Little Devil I(树链剖分)(2014 Multi-University Training Contest 4)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4897 Problem Description There is an old country and ...

  8. hdu 4857 逃生

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4857 逃生 Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能 ...

  9. (hdu) 4857 逃生 (拓扑排序+优先队列)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857 Problem Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄 ...

随机推荐

  1. 【ORACLE】重写控制文件

    [oracle@rac01 ~]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Thu Mar 15 23:45:02 ...

  2. JVM源码---教你傻瓜式编译openjdk7(JAVA虚拟机爱好者必看)

    LZ经过一个星期断断续续的研究,终于成功的搞定了JDK的成功编译与调试.尽管网络上的教程也有不少,包括源码中也有自带的编译步骤说明,但真正自己动手的话,还是会遇到不少意料之外的错误. 为了方便各位猿友 ...

  3. OpenMPI源码剖析:网络通信原理(二) 如何选择网络协议?

    因为比较常用的是 TCP 协议,所以在 opal/mca/btl/tcp/btl_tcp.h 头文件中找到对应的 struct mca_btl_tcp_component_t { mca_btl_ba ...

  4. CentOS7安装OpenStack(Rocky版)-01.控制节点的系统环境准备

    分享一下Rocky版本的OpenStack安装管理经验: OpenStack每半年左右更新一版,目前是版本是201808月发布的版本-R版(Rocky),目前版本安装方法优化较好,不过依然是比较复杂 ...

  5. X86主要的几种寻址方式

    一.首先 P33: 严格来说有三种寻址方式 与数据有关的寻址方式 与转移指令或过程调用指令有关的寻址方式 与IO指令有关的寻址方式 这篇博客只讲1.2两条 二.然后 1. 与数据有关的寻址方式 数据, ...

  6. [2017BUAA软工助教]剩余个人作业与deadline

    软件工程剩余作业与deadline 标签(空格分隔): 软件工程 一.个人阅读作业+总结 对软件工程的学习做一个总结. 阅读下列关于软件开发本质和开发方法的博客/文章,结合自己在个人项目/结对编程/团 ...

  7. 20170831 php

    今天开始学习php 发现这个网站教程感觉入门很轻松 http://www.php.cn/code/25.html 配置环境遇到了端口占用的问题 解决方案: http://www.weekdian.co ...

  8. python3 selenium打开Chrome报错闪退问题

    ChromeDriver不匹配 Google Chrome 已是最新版本 版本 64.0.3282.186(正式版本) (32 位)   ChromeDriver应该选择2.35 下载链接:https ...

  9. ffmpeg格式转换

    遇到有些wav文件在ubuntu下无法打开的情况,可以使用ffmpeg进行格式转换即可 ffmpeg -i 0.wav test.wav

  10. VS2013简单的单元测试

    安装过程本人在此就不做多余的说明,如果一个程序员连一个软件都无法安装那我也醉了,其次就是希望我们不要为了完成作业而去用VS,下面我具体说一下单元测试. 第一步,文件→新建一个项目,具体操作如下图 打开 ...