\(\color{#0066ff}{ 题目描述 }\)

给你一棵n个点的树,编号1~n。每个点可以是黑色,可以是白色。初始时所有点都是黑色。下面有两种操作请你操作给我们看:

0 u:询问有多少个节点v满足路径u到v上所有节点(包括)都拥有相同的颜色
1 u:翻转u的颜色

\(\color{#0066ff}{输入格式}\)

一行一个整数n

接下来n-1行,每行两个整数表示一条边

接下来一行一个整数m表示操作次数

接下来m行,每行两个整数分别表示操作类型和被操作节点

\(\color{#0066ff}{输出格式}\)

对每个询问操作输出相应的结果

\(\color{#0066ff}{输入样例}\)

5
1 2
1 3
1 4
1 5
3
0 1
1 1
0 1

\(\color{#0066ff}{输出样例}\)

5
1

\(\color{#0066ff}{数据范围与提示}\)

对所有数据,\(1\leq n \leq 10^5\),\(1\leq m \leq 10^5\)

\(\color{#0066ff}{ 题解 }\)

容易想到,开两个LCT分别维护黑白两种颜色

然后修改颜色的时候,暴力cut相邻的边,link相邻的边

然而。。。存在一种东东叫菊花图。。。

显然很容易就被Hack掉了

正常LCT的题目中,如果有边权,我们肯定是边权转到点权上,这样才好维护

然而。。。本题就是与众不同,他要把点权转到边权上!

把每个点的点权转到它与父亲的边上,特别的,开一个0号节点,\(0-1\)存的是1的点权

然后询问的联通块即为所在联通块根的siz-1,注意,根的颜色跟其它点不同

因为根父亲的边不在这里!

因此仍然是LCT维护子树大小即可

对于改变颜色的问题,发现只需要断一条边即可

所以复杂度就保证了

#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 1e5 + 10;
struct LCT {
protected:
struct node {
node *ch[2], *fa;
int siz, tot;
node(int siz = 0, int tot = 1): siz(siz), tot(tot) { ch[0] = ch[1] = fa = NULL; }
void upd() {
tot = siz + 1;
if(ch[0]) tot += ch[0]->tot;
if(ch[1]) tot += ch[1]->tot;
}
bool ntr() { return fa && (fa->ch[0] == this || fa->ch[1] == this); }
bool isr() { return fa->ch[1] == this; }
}pool[maxn];
void rot(node *x) {
node *y = x->fa, *z = y->fa;
bool k = x->isr(); node *w = x->ch[!k];
if(y->ntr()) z->ch[y->isr()] = x;
(x->ch[!k] = y)->ch[k] = w;
(y->fa = x)->fa = z;
if(w) w->fa = y;
y->upd(), x->upd();
}
void splay(node *o) {
while(o->ntr()) {
if(o->fa->ntr()) rot(o->isr() ^ o->fa->isr()? o : o->fa);
rot(o);
}
}
void access(node *x) {
for(node *y = NULL; x; x = (y = x)->fa) {
splay(x);
if(x->ch[1]) x->siz += x->ch[1]->tot;
if((x->ch[1] = y)) x->siz -= y->tot;
x->upd();
}
}
node *findroot(node *o) {
access(o), splay(o);
while(o->ch[0]) o = o->ch[0];
return splay(o), o;
}
public:
void link(int l, int r) {
node *x = pool + l, *y = pool + r;
access(x), splay(x);
x->fa = y;
access(y), splay(y);
y->siz += x->tot;
y->upd();
}
void cut(int l, int r) {
node *x = pool + l;
access(x), splay(x);
x->ch[0] = x->ch[0]->fa = NULL;
x->upd();
}
int query(int p) {
node *o = findroot(pool + p);
return o->ch[1]->tot;
}
}s[2];
struct node {
int to;
node *nxt;
node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
};
node *head[maxn];
int n, m, f[maxn], col[maxn];
void add(int from, int to) {
head[from] = new node(to, head[from]);
}
void dfs(int x, int fa) {
f[x] = fa;
s[1].link(x, fa);
for(node *i = head[x]; i; i = i->nxt)
if(i->to != fa)
dfs(i->to, x);
}
int main() {
n = in();
int x, y;
for(int i = 1; i <= n; i++) col[i] = 1;
for(int i = 1; i < n; i++) x = in(), y = in(), add(x, y), add(y, x);
dfs(1, 0);
for(m = in(); m --> 0;) {
x = in(), y = in();
if(x == 0) printf("%d\n", s[col[y]].query(y));
if(x == 1) s[col[y]].cut(y, f[y]), s[col[y] ^= 1].link(y, f[y]);
}
return 0;
}

SP16549 QTREE6 - Query on a tree VI LCT维护颜色联通块的更多相关文章

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

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

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

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

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

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

  4. [QTree6]Query on a tree VI

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

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

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

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

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

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

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

  8. BZOJ 3637: Query on a tree VI LCT_维护子树信息_点权转边权_好题

    非常喜欢这道题. 点权转边权,这样每次在切断一个点的所有儿子的时候只断掉一条边即可. Code: #include <cstring> #include <cstdio> #i ...

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

随机推荐

  1. QQ控件时光轴特效总结

    1.插入HTML数据 插入html代码,一般的做法是通过document.getElementById("").innerHTML来实现. 然而在该控件中,它通过JS replac ...

  2. 调试json

    console.log("======================") // 转对象 //var obj = eval('(' + data + ')'); // 转对象 // ...

  3. C#调用带返回值的存储过程

    ()在SQL Server中建立如下的存储过程: set ANSI_NULLS ON set QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[GetNa ...

  4. Hadoop集群 能打开50070端口不能打开8088端口 web浏览器界面

    两天时间,知道现在才把这个东西解决  解决的灵感来源于百度知道一句话谢谢这个哥们 谢谢这个哥们! ​我的目录是在/home/hadoop/tmp  大家如果遇到这个问题,希望能按照我的办法去试一下 2 ...

  5. [Python Study Notes]pd.read_csv()函数读取csv文件绘图

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ...

  6. Servlet开发中注意的细节问题

    客户端访问服务器的时候是通过URL访问的,所以我们要想用浏览器访问我们的Servlet的时候,我们就需要将我们的Servlet映射到一个URL上(通过我们的web.xml文件中的<servler ...

  7. 第四天:servlet的生命周期和一些细节问题

    1.  servlet的生命周期: a)  流程 i.  Web服务器首先会检查是否装载了该servlet的实例对象.如果装载了直接进行第四步. ii.  装载并创建该servlet的实例对象. ii ...

  8. ROS Learning-010 beginner_Tutorials 编写简单的启动脚本文件(.launch 文件)

    ROS Indigo beginner_Tutorials-09 编写简单的启动脚本文件 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14.0 ...

  9. Linux wine

    一.简介 Wine是Wine Is Not an Emulator(Wine不是模拟器)的缩写,其实是一个转换层(或程序装入器),能够在Linux及与POSIX兼容的其他类似操作系统上运行Window ...

  10. Entity Relationships

    Entity Relationships: Here, you will learn how entity framework manages the relationships between en ...