zoukankan      html  css  js  c++  java
  • SP16549 QTREE6

    (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}{数据范围与提示})

    对所有数据,(1leq n leq 10^5)(1leq 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
    ", 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;
    }
    
  • 相关阅读:
    JDK下载 安装 配置
    C#中的委托与事件 笔记
    转载 -- C# 中的委托和事件
    Laravel5 路由问题 /home页面无法访问
    eclipse的android智能提示设置
    svn在linux下的使用(ubuntu命令行模式操作svn)
    gdb结合coredump定位崩溃进程
    Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析
    struct的初始化,拷贝及指针成员的使用技巧
    C++ 资源大全
  • 原文地址:https://www.cnblogs.com/olinr/p/10397235.html
Copyright © 2011-2022 走看看