BZOJ3720 Gty的妹子树

[Solution]

It is likely that you need to modify the dfs order by a dynamic data structure. However, n is not big enough to use log-level algorithm. Divide the tree into sqrt(n) parts. Then use treaps to modify each part.


[Code]

So ugly and slow.


#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <algorithm>

using namespace std;

struct edge {
	int t;
	edge *next;
};

template <class _INT>
void readInt(_INT& s) {
	int d;
	bool nag = 0;
	s = 0;
	while (!isdigit(d = getchar()))
		if (d == '-')
			nag = 1;
	while ((s = s * 10 + d - 48), isdigit(d = getchar()));
	if (nag)
		s = -s;
}

const int maxn = 60009;

int n, m, lans, fa[maxn], w[maxn], d[maxn];
int pcsz, tp, fp[maxn], pd0[maxn], prt[maxn], pfa[maxn];
edge *ht[maxn], *hp[maxn], *ep, elst[maxn * 6];

namespace treap {//{{{
	int tn, ls[maxn], rs[maxn], vl[maxn], w[maxn], sz[maxn];
	inline void init() {
		tn = 0;
		sz[0] = 0;
	}
	inline int newNode(int v) {
		++ tn;
		ls[tn] = 0;
		rs[tn] = 0;
		vl[tn] = v;
		sz[tn] = 1;
		w[tn] = rand();
		return tn;
	}
	inline void lRot(int& p) {
		int q = rs[p];
		rs[p] = ls[q];
		ls[q] = p;
		sz[q] = sz[p];
		sz[p] = sz[ls[p]] + sz[rs[p]] + 1;
		p = q;
	}
	inline void rRot(int& p) {
		int q = ls[p];
		ls[p] = rs[q];
		rs[q] = p;
		sz[q] = sz[p];
		sz[p] = sz[ls[p]] + sz[rs[p]] + 1;
		p = q;
	}
	inline void maintain(int& p, bool d) {
		if (d) {
			if (w[ls[p]] > w[p])
				rRot(p);
		}
		else
			if (w[rs[p]] > w[p])
				lRot(p);
	}
	void ins(int& p, int v) {
		if (!p)
			p = newNode(v);
		else {
			if (v < vl[p])
				ins(ls[p], v);
			else
				ins(rs[p], v);
			++ sz[p];
			maintain(p, v < vl[p]);
		}
	}
	bool ers(int& p, int v) {
		if (!p)
			return 0;
		else if (vl[p] == v) {
			if (!ls[p])
				p = rs[p];
			else if (!rs[p])
				p = ls[p];
			else {
				int q = ls[p];
				while (rs[q])
					q = rs[q];
				vl[p] = vl[q];
				-- sz[p];
				return ers(ls[p], vl[p]);
			}
			return 1;
		}
		else {
			-- sz[p];
			if (v < vl[p])
				return ers(ls[p], v);
			else
				return ers(rs[p], v);
		}
	}
	int cntUpper(int p, int v) {
		if (!p)
			return 0;
		else if (vl[p] > v)
			return sz[rs[p]] + 1 + cntUpper(ls[p], v);
		else
			return cntUpper(rs[p], v);
	}
};//}}}

inline void addEdge(edge** head, int u, int v) {
	ep-> t = v;
	ep-> next = head[u];
	head[u] = ep ++;
}

void buildTree() {
	static int q[maxn];
	int hd = 0, tl = 1;
	for (int i = 0; i < maxn; ++ i)
		fa[i] = -1;
	q[hd] = 1;
	fa[1] = 0;
	d[1] = 1;
	fp[0] = 0;
	tp = 0;
	while (hd < tl) {
		int p = q[hd ++];
		if (fa[p] && d[p] - pd0[fp[fa[p]]] < pcsz) {
			fp[p] = fp[fa[p]];
			treap :: ins(prt[fp[p]], w[p]);
		}
		else {
			fp[p] = ++ tp;
			treap :: ins(prt[fp[p]], w[p]);
			pd0[fp[p]] = d[p];
			pfa[fp[p]] = fp[fa[p]];
			addEdge(hp, fp[fa[p]], fp[p]);
		}
		for (edge* e = ht[p]; e; e = e-> next)
			if (fa[e-> t] == -1) {
				fa[e-> t] = p;
				d[e-> t] = d[p] + 1;
				q[tl ++] = e-> t;
			}
	}
}

int query(int p, int v) {
	static int q[maxn], qp[maxn];
	int hd = 0, tl = 1, tq = 0, s = 0, p0 = fp[p];
	q[hd] = p;
	while (hd < tl) {
		int p = q[hd ++];
		if (w[p] > v)
			s ++;
		for (edge* e = ht[p]; e; e = e-> next)
			if (fa[e-> t] == p) {
				if (fp[e-> t] == fp[p])
					q[tl ++] = e-> t;
				else
					qp[tq ++] = fp[e-> t];
			}
	}
	hd = 0, tl = tq;
	while (hd < tl) {
		int p = qp[hd ++];
		if (p != p0)
			s += treap :: cntUpper(prt[p], v);
		for (edge* e = hp[p]; e; e = e-> next)
			if (pfa[e-> t] == p)
				qp[tl ++] = e-> t;
	}
	return s;
}

int main() {
	srand(45239423);
	treap :: init();
	for (int i = 0; i < maxn; ++ i)
		prt[i] = 0;
	ep = elst;
	readInt(n);
	for (pcsz = 0; pcsz * pcsz < n * 2; ++ pcsz);
	lans = 0;
	for (int i = 0; i < n - 1; i ++) {
		int u, v;
		readInt(u);
		readInt(v);
		addEdge(ht, u, v);
		addEdge(ht, v, u);
	}
	for (int i = 1; i <= n; i ++)
		readInt(w[i]);
	buildTree();
	readInt(m);
	while (m --) {
		int opt, u, x;
		readInt(opt);
		readInt(u);
		readInt(x);
		u ^= lans;
		x ^= lans;
		if (u > n) {
			for (int i = 0; i < m; ++ i)
				puts("WAAAAAAAAAA");
			return 12345;
		}
		if (opt == 0)
			printf("%d\n", (lans = query(u, x)));
		else if (opt == 1) {
			treap :: ers(prt[fp[u]], w[u]);
			w[u] = x;
			treap :: ins(prt[fp[u]], w[u]);
		}
		else if (opt == 2) {
			n ++;
			addEdge(ht, u, n);
			fa[n] = u;
			w[n] = x;
			int p = n;
			d[p] = d[fa[p]] + 1;
			if (d[p] - pd0[fp[fa[p]]] < pcsz) {
				fp[p] = fp[fa[p]];
				treap :: ins(prt[fp[p]], w[p]);
			}
			else {
				fp[p] = ++ tp;
				treap :: ins(prt[fp[p]], w[p]);
				pd0[fp[p]] = d[p];
				pfa[fp[p]] = fp[fa[p]];
				addEdge(hp, fp[fa[p]], fp[p]);
			}
		}
		lans = 0;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值