[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分离颜色 每个颜色在边上. 仅保留连通块顶部不 ...
随机推荐
- Java并发编程(3) JUC中的锁
一 前言 前面已经说到JUC中的锁主要是基于AQS实现,而AQS(AQS的内部结构 .AQS的设计与实现)在前面已经简单介绍过了.今天记录下JUC包下的锁是怎么基于AQS上实现的 二 同步锁 同步锁不 ...
- 【codeforces】【比赛题解】#960 CF Round #474 (Div. 1 + Div. 2, combined)
终于打了一场CF,不知道为什么我会去打00:05的CF比赛…… 不管怎么样,这次打的很好!拿到了Div. 2选手中的第一名,成功上紫! 以后还要再接再厉! [A]Check the string 题意 ...
- 【NOIP题解】NOIP2017 TG D2T3 列队
列队,NOIP2017 TG D2T3. 树状数组经典题. 题目链接:洛谷. 题意: Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. ...
- docker 错误排查:无法进入容器.
docker 错误排查:无法进入容器. #docker exec -it 3c1d bash rpc error: code = 2 desc = oci runtime error: exec fa ...
- 一步一步搭建11gR2 rac+dg之配置单实例的DG(八)【转】
RAC主库配置单实例ActiveDataguard 本文文档结构: 这里配置的过程中需要注意的一项是多看看rac1和rac2以及dg的告警日志会对配置过程有更深刻的理解...配置oracle rac的 ...
- (三)使用XML配置SQL映射器
SqlSessionFactoryUtil.java package com.javaxk.util; import java.io.IOException; import java.io.Input ...
- (一)SpringMVC
第一章 问候SpringMVC 第一节 SpringMVC简介 SpringMVC是一套功能强大,性能强悍,使用方便的优秀的MVC框架 下载和安装Spring框架: 登录http://repo.spr ...
- supervisor管理uwsgi
1. 前言 传统的管理uwsgi服务: 1. 通过shell脚本来编写start restart stop函数来控制 2. 比较麻烦,有时候控制写的烂,还会出现意想不到的错误 supervisor进行 ...
- 20155225 2016-2017-2 《Java程序设计》第十周学习总结
20155225 2016-2017-2 <Java程序设计>第十周学习总结 教材学习内容总结 22章网络 22.1网络概览 22.2超文本传输协议(HTTP) 22.2.1 HTTP请求 ...
- CVE-2013-0025
Microsoft IE ‘SLayoutRun’释放后重用漏洞(CNNVD-201302-197) Microsoft Internet Explorer是微软Windows操作系统中默认捆绑的WE ...