码迷,mamicode.com
首页 > 其他好文 > 详细

SPOJ QTREE6 - Query on a tree VI(lct)

时间:2020-05-19 23:14:24      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:upd   query   子节点   return   spoj   方向   namespace   name   using   

https://www.spoj.com/problems/QTREE6/

考虑对0颜色和1颜色分别维护定根(no reverse)lct。

即在\(c[x]\)的lct上给\(x\)\(fa[x]\)连一条边。

修改直接link、cut。

查询x的话,考虑access走到最上面的点,这个点实际上和x是不连通的,但是它的子节点(x方向的)的子树就是联通块大小。

所以lct要顺便维护子树和。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 1e5 + 5;

int n, x, y;

vector<int> e[N];
#define pb push_back
#define si size()

int fa[N];

void dg(int x) {
	ff(_y, 0, e[x].si) {
		int y = e[x][_y];
		if(y == fa[x]) continue;
		fa[y] = x;
		dg(y);
	}
}

int id[N][2], td, id2[N];

struct lct {
	#define x0 t[x][0]
	#define x1 t[x][1]
	int fa[N], pf[N], t[N][2], s[N], ps[N];
	int lr(int x) { return t[fa[x]][1] == x;}
	void upd(int x) {
		if(x) s[x] = 1 + ps[x] + s[x0] + s[x1];
	}
	void ro(int x) {
		int y = fa[x], k = lr(x);
		t[y][k] = t[x][!k]; if(t[x][!k]) fa[t[x][!k]] = y;
		fa[x] = fa[y]; if(fa[y]) t[fa[y]][lr(y)] = x;
		fa[y] = x, t[x][!k] = y, pf[x] = pf[y];
		upd(y); upd(x);
	}
	void sp(int x, int y) {
		for(; fa[x] != y; ro(x)) if(fa[fa[x]] != y)
			ro(lr(x) == lr(fa[x]) ? fa[x] : x);
	}
	void ac(int x) {
		int xx = x;
		for(int y = 0; x; ) {
			sp(x, 0), fa[x1] = 0, pf[x1] = x;
			ps[x] += s[x1];
			
			x1 = y, fa[y] = x, pf[y] = 0;
			ps[x] -= s[y];
			
			upd(x), y = x, x = pf[x];
		}
		sp(xx, 0);
	}
	void link(int x, int y) {
		ac(y); ac(x);
		pf[x] = y; ps[y] += s[x];
		upd(y);
		ac(x);
	}
	void cut(int x, int y) {
		ac(x); sp(y, 0);
		t[y][1] = fa[x] = pf[x] = 0;
		upd(y);
	}
	int fl(int x) { return x0 ? fl(x0) : x;}
	int qry(int x) {
		ac(x);
		int y = fl(x);
		sp(y, 0);
		return s[t[y][1]];
	}
} l[2];

int c[N];

int m, op;

int main() {
	scanf("%d", &n);
	fo(i, 1, n - 1) {
		scanf("%d %d", &x, &y);
		e[x].pb(y); e[y].pb(x);
	}
	dg(1);
	fa[1] = n + 1;
	fo(i, 1, n + 1) fo(j, 0, 1)
		l[j].s[i] = 1;
	fo(i, 1, n) {
		c[i] = 1;
		l[1].link(i, fa[i]);
	}
	scanf("%d", &m);
	fo(i, 1, m) {
		scanf("%d %d", &op, &x);
		if(op == 1) {
			l[c[x]].cut(x, fa[x]);
			c[x] = !c[x];
			l[c[x]].link(x, fa[x]);
		} else {
			pp("%d\n", l[c[x]].qry(x));
		}
	}
}

SPOJ QTREE6 - Query on a tree VI(lct)

标签:upd   query   子节点   return   spoj   方向   namespace   name   using   

原文地址:https://www.cnblogs.com/coldchair/p/12919594.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!