[CodeChef-QTREE6]Query on a tree VI
题目大意:
给你一棵黑白树,每个点默认是白色,要求支持以下两种操作:
1.改变一个点的颜色;
2.除去连接不同颜色的点的边,求某个点连通块的大小。
思路:
对原树维护两个树链剖分,
一棵维护当点x为白色时,以它为根结点的白色的子树大小;
另一棵维护当点x为黑色时,以它为根结点的黑色的子树大小。(两者均不考虑x的实际颜色)
方便起见,这里我们用q表示同一个连通分量中,深度最浅的祖先。
询问一个点时,相当于在询问q的值。
修改一个点时,相当于在原来颜色的树剖上将x到q的路径上的所有点同时减去x同色子树的大小,然后在新的颜色的树剖上将x到q路径上的所有点同时加上x同色子树的大小。
如果对每个点都加/减显然不方便,因此我们可以用一些数据结构(线段树/树状数组)来维护差分。
注意这道题会卡常,要么对每一条链建线段树,要么就用树状数组。
接下来的问题是如何找到祖先q。
如果暴力往上找,时间复杂度是O(n)的,显然会TLE。
假如我们能够直接判断某一个树链上的点是否是同一种颜色,那就可以直接往上跳了。
如何直接判断?
考虑用0代表白色,1代表黑色,如果当这条链上所有点的权值和等于这条链上结点的个数,或等于0,那么肯定是同一种颜色的。
这样我们可以直接维护树上前缀和,询问的时候减一下就可以了。
最后还剩半条链没法跳的时候可以二分中间的结点。
#include<cstdio>
#include<cctype>
#include<vector>
inline int getint() {
char ch;
while(!isdigit(ch=getchar()));
int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int V=;
std::vector<int> e[V];
inline void add_edge(const int &u,const int &v) {
e[u].push_back(v);
}
int par[V],size[V],son[V],top[V],id[V],dep[V],id2[V],n;
bool col[V];
void dfs1(const int &x,const int &p) {
par[x]=p;
size[x]=;
dep[x]=dep[p]+;
for(unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==p) continue;
dfs1(y,x);
size[x]+=size[y];
if(size[y]>size[son[x]]) {
son[x]=y;
}
}
}
void dfs2(const int &x) {
id[x]=++n;
id2[n]=x;
top[x]=x==son[par[x]]?top[par[x]]:x;
if(son[x]) dfs2(son[x]);
for(unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par[x]||y==son[x]) continue;
dfs2(y);
}
}
class FenwickTree {
private:
int val[V];
int lowbit(const int &x) {
return x&-x;
}
public:
void modify(int p,const int &x) {
while(p<=n) {
val[p]+=x;
p+=lowbit(p);
}
}
int query(int p) {
int ret=;
while(p) {
ret+=val[p];
p-=lowbit(p);
}
return ret;
}
};
FenwickTree t[];
bool check(const int &u,const int &m) {
return t[].query(id[u])-t[].query(id[m]-)==col[u]*(dep[u]-dep[m]+);
}
inline int get_anc(int u) {
while(top[u]!=&&check(u,top[u])) {
if(col[par[top[u]]]==col[u]) {
u=par[top[u]];
} else {
return top[u];
}
}
int l=id[top[u]],r=id[u];
while(l<=r) {
const int mid=(l+r)>>;
if(check(u,id2[mid])) {
r=mid-;
} else {
l=mid+;
}
}
return id2[r+];
}
inline void modify2(int x,int y,const int &k,const bool &c) {
while(top[x]!=top[y]) {
t[c].modify(id[top[x]],k);
t[c].modify(id[x]+,-k);
x=par[top[x]];
}
t[c].modify(id[y],k);
t[c].modify(id[x]+,-k);
}
inline void modify(const int &u) {
if(u!=) modify2(par[u],par[get_anc(u)],-t[col[u]].query(id[u]),col[u]);
t[].modify(id[u],col[u]?-:);
col[u]^=true;
if(u!=) modify2(par[u],par[get_anc(u)],t[col[u]].query(id[u]),col[u]);
}
inline int query(const int &u) {
return t[col[u]].query(id[get_anc(u)]);
}
int main() {
int n=getint();
for(register int i=;i<n;i++) {
const int u=getint(),v=getint();
add_edge(u,v);
add_edge(v,u);
}
dfs1(,);
dfs2();
for(register int i=;i<=n;i++) {
t[].modify(id[i],size[i]);
t[].modify(id[i]+,-size[i]);
}
t[].modify(,);
for(register int m=getint();m;m--) {
const int t=getint(),u=getint();
if(t) {
modify(u);
} else {
printf("%d\n",query(u));
}
}
return ;
}
[CodeChef-QTREE6]Query on a tree VI的更多相关文章
- QTREE6 - Query on a tree VI 解题报告
QTREE6 - Query on a tree VI 题目描述 给你一棵\(n\)个点的树,编号\(1\)~\(n\).每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我 ...
- bzoj3637 CodeChef SPOJ - QTREE6 Query on a tree VI 题解
题意: 一棵n个节点的树,节点有黑白两种颜色,初始均为白色.两种操作:1.更改一个节点的颜色;2.询问一个节点所处的颜色相同的联通块的大小. 思路: 1.每个节点记录仅考虑其子树时,假设其为黑色时所处 ...
- SP16549 QTREE6 - Query on a tree VI LCT维护颜色联通块
\(\color{#0066ff}{ 题目描述 }\) 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v ...
- SPOJ QTREE6 Query on a tree VI 树链剖分
题意: 给出一棵含有\(n(1 \leq n \leq 10^5)\)个节点的树,每个顶点只有两种颜色:黑色和白色. 一开始所有的点都是黑色,下面有两种共\(m(1 \leq n \leq 10^5) ...
- [QTree6]Query on a tree VI
Description: 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v满足路径u到v上所有节点(包括 ...
- 洛谷SP16549 QTREE6 - Query on a tree VI(LCT)
洛谷题目传送门 思路分析 题意就是要维护同色连通块大小.要用LCT维护子树大小就不说了,可以看看蒟蒻的LCT总结. 至于连通块如何维护,首先肯定可以想到一个很naive的做法:直接维护同色连通块,每次 ...
- SPOJ 16549 - QTREE6 - Query on a tree VI 「一种维护树上颜色连通块的操作」
题意 有操作 $0$ $u$:询问有多少个节点 $v$ 满足路径 $u$ 到 $v$ 上所有节点(包括)都拥有相同的颜色$1$ $u$:翻转 $u$ 的颜色 题解 直接用一个 $LCT$ 去暴力删边连 ...
- SP16549 QTREE6 - Query on a tree VI(LCT)
题意翻译 题目描述 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v满足路径u到v上所有节点(包括)都拥 ...
- bzoj 3637: Query on a tree VI 树链剖分 && AC600
3637: Query on a tree VI Time Limit: 8 Sec Memory Limit: 1024 MBSubmit: 206 Solved: 38[Submit][Sta ...
- QTREE6&&7 - Query on a tree VI &&VII
树上连通块 不用具体距离,只询问连通块大小或者最大权值 可以类比Qtree5的方法,但是记录东西很多,例如子树有无0/1颜色等 一个trick,两个LCT分离颜色 每个颜色在边上. 仅保留连通块顶部不 ...
随机推荐
- 20155303 2016-2017-2 《Java程序设计》第三周学习总结
20155303 2016-2017-2 <Java程序设计>第三周学习总结 教材学习内容总结 第四章 学会如何查询Java API文件对于Java的学习很有帮助,可以了解到如何使用各种方 ...
- Java枚举类型的用法
JDK1.5引入了新的类型——枚举.在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便. 1.用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fia ...
- Ubuntu使用apt-get upgrade升级时出错
今天在按照常规的sudo apt-get update更新软件列表后,再使用sudo apt-get upgrade升级软件时,出现了以下的错误: 正在设置 linux-image-extra-4.4 ...
- Ubuntu下使用virtualenv
Ubuntu 18.04,Python 3.6.5(最新3.7),virtualenv 16.0.0, 即将在Ubuntu上大张旗鼓地干活啦!那么,将之前安装的virtualenv运行起来吧(前面都是 ...
- 本地为Windows,使用Xshell登录Linux云主机
以某东的云主机为实例 1. 下载并安装远程登录软件 下载Xshell软件 下载后双击xshell5_5.0.1332.exe进行安装 2. 安装完成,打开Xshell,并点击新建,根据要求输入相应参数 ...
- Ansible之tags介绍
本节内容: tags介绍 一.tags介绍 我们每次改完配置文件,比如上一篇博客中的的apache.yml,没必要把整个playbook都运行一遍,只需要运行改变了的task.我们可以给task一个标 ...
- ElasticSearch实战概要
最近中美关系越来越紧张,国内经济下滑,股市一片惨淡,互联网行业越来越不景气,动不动都是跌掉几千亿市值,来写一些文档来抚慰这颗受伤的心吧... 随着互联网的发展,数据越来越重要,每个公司保存的数据也是越 ...
- php 根据ip获取城市以及网络运营商名称(利用qqwry.dat)
根据用户IP地址判定出所在城市以及网络运营商 qqwry.dat下载地址:http://files.cnblogs.com/guangxiaoluo/qqwry.rar 解压出来即可 //获取用户真 ...
- 【UOJ】#37. 【清华集训2014】主旋律
题解 一道,神奇的题= = 我们考虑正难则反,我们求去掉这些边后有多少图不是强连通的 怎么求呢,不是强连通的图缩点后一定是一个DAG,并且这个DAG里面有两个点 我们想一下,如果我们把1当成入度为0的 ...
- (转)看懂UML类图
转自:http://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html 这里不会将UML的各种元素都提到,我只想讲讲类图中各个类之间的关 ...