题目大意:
  给你一棵黑白树,每个点默认是白色,要求支持以下两种操作:
    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的更多相关文章

  1. QTREE6 - Query on a tree VI 解题报告

    QTREE6 - Query on a tree VI 题目描述 给你一棵\(n\)个点的树,编号\(1\)~\(n\).每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我 ...

  2. bzoj3637 CodeChef SPOJ - QTREE6 Query on a tree VI 题解

    题意: 一棵n个节点的树,节点有黑白两种颜色,初始均为白色.两种操作:1.更改一个节点的颜色;2.询问一个节点所处的颜色相同的联通块的大小. 思路: 1.每个节点记录仅考虑其子树时,假设其为黑色时所处 ...

  3. SP16549 QTREE6 - Query on a tree VI LCT维护颜色联通块

    \(\color{#0066ff}{ 题目描述 }\) 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v ...

  4. SPOJ QTREE6 Query on a tree VI 树链剖分

    题意: 给出一棵含有\(n(1 \leq n \leq 10^5)\)个节点的树,每个顶点只有两种颜色:黑色和白色. 一开始所有的点都是黑色,下面有两种共\(m(1 \leq n \leq 10^5) ...

  5. [QTree6]Query on a tree VI

    Description: 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v满足路径u到v上所有节点(包括 ...

  6. 洛谷SP16549 QTREE6 - Query on a tree VI(LCT)

    洛谷题目传送门 思路分析 题意就是要维护同色连通块大小.要用LCT维护子树大小就不说了,可以看看蒟蒻的LCT总结. 至于连通块如何维护,首先肯定可以想到一个很naive的做法:直接维护同色连通块,每次 ...

  7. SPOJ 16549 - QTREE6 - Query on a tree VI 「一种维护树上颜色连通块的操作」

    题意 有操作 $0$ $u$:询问有多少个节点 $v$ 满足路径 $u$ 到 $v$ 上所有节点(包括)都拥有相同的颜色$1$ $u$:翻转 $u$ 的颜色 题解 直接用一个 $LCT$ 去暴力删边连 ...

  8. SP16549 QTREE6 - Query on a tree VI(LCT)

    题意翻译 题目描述 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v满足路径u到v上所有节点(包括)都拥 ...

  9. 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 ...

  10. QTREE6&&7 - Query on a tree VI &&VII

    树上连通块 不用具体距离,只询问连通块大小或者最大权值 可以类比Qtree5的方法,但是记录东西很多,例如子树有无0/1颜色等 一个trick,两个LCT分离颜色 每个颜色在边上. 仅保留连通块顶部不 ...

随机推荐

  1. 解决 Electron 包下载太慢问题

    项目下新建 .npmrc 文件,加入如下配置: electron_mirror=https://npm.taobao.org/mirrors/electron/ 即使用淘宝的源,重新 npm inst ...

  2. 2016.5.21——Compare Version Numbers

    Compare Version Numbers 本题收获: 1.字符串型数字转化为整型数字的方法:s[i] - '0',( 将字母转化为数字是[i]-'A'   ) 2.srt.at(),substr ...

  3. 【bzoj题解】题解传送门

    如题,题解传送门: 1001 1008 1012

  4. MySQL 删除数据

    删除数据的语句有三种:DELETE.DROP.TRUNCATE. 1.DELETE语句 DELETE 语句用于删除表中的行. 语法 DELETE FROM 表名称 WHERE 列名称 = 值 例如 - ...

  5. mac 升级10.12 php debug 环境 跑不起的解决 解决方案

    1:  mac 升级后发现 php从原来的5.5  升级为 5.6 了...   所以以前 php.ini 里面的配置全部都没有了. mac 给我们做了备份2:  没办法只能升级php对应的插件到5. ...

  6. docker强制关闭命令

    删除容器: 优雅的关闭容器:docker stop  容器id/容器名字 强制关闭容器:docker kill 容器id/容器名字 删除镜像: docker rmi 容器id/容器名字

  7. Ubuntu下软件安装方式、PATH配置、查找安装位置

    Ubuntu 18.04, 安装方式 目前孤知道的Ubuntu下安装软件方式有3种(命令): 1.make 2.apt/apt-get 3.dpkg 方式1基于软件源码安装,需要经历配置(可选).编译 ...

  8. Nginx - 日志格式及输出

    1. 前言 在 Nginx 服务器中,如果想对日志输出进行控制还是很容易的.Nginx 服务器提供了一个 HttpLogModule 模块,可以通过它来设置日志的输出格式. 2. HttpLogMod ...

  9. Spring框架(管理事务)

    Spring底层使用Transaction事物模板来进行操作.具体操作: 1.service 需要获得 TransactionTemplate 2.spring 配置模板,并注入给service 3. ...

  10. C#设置窗体中的窗体随主窗体大小变化而变化

    form2 f=new form2(); f.Size=this.Size; f.Location=this.Location; f.showdialog(); 作者:耑新新,发布于  博客园 转载请 ...