[ZJOI2008]树的统计Count

第一道 query on a tree 类的题目,帖个代码吧。

LCT 果断被虐爆了。。。不知多少版去了。。。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#include <map>
#define maxn 30005
#define not_root(p) (p->f != null && (p == p->f->c[0] || p == p->f->c[1]))

struct node {
	int k, sum, maxi, hehe;
	node * f, * c[2];
} null[maxn] = {(node) {0, 0, - maxn}}, * to[maxn];

void update(node * p)
{
	p->sum = p->c[0]->sum + p->c[1]->sum + p->k;
	p->maxi = max(p->c[0]->maxi, p->c[1]->maxi);
	if (p->k > p->maxi) p->maxi = p->k;
}

void rotate(node * p)
{
	node * q = p->f; bool k = p == q->c[0];
	p->c[k]->f = q, q->c[! k] = p->c[k], p->c[k] = q;
	if (q == q->f->c[0]) q->f->c[0] = p;
	if (q == q->f->c[1]) q->f->c[1] = p;
	p->f = q->f, q->f = p, update(q);
}

void splay(node * p)
{
	while (not_root(p))
		if (not_root(p->f))
			if ((p == p->f->c[0]) ^ (p->f == p->f->f->c[0]))
				rotate(p), rotate(p);
			else rotate(p->f), rotate(p);
		else {rotate(p); break;}
	update(p);
}

pair <int, int> access(node * p)
{
	int x, y; node * q = null;
	for (; p != null; p = p->f)
		{
			splay(p);
			if (p->f == null)
				{
					x = p->c[1]->sum + p->k + q->sum;
					y = max(p->c[1]->maxi, q->maxi);
					if (p->k > y) y = p->k;
				}
			p->c[1] = q, update(p), q = p;
		}
	return make_pair(x, y);
}

void read(int & x)
{
	char c = getchar(), d = 0;
	while (c != '-' && ('0' > c || c > '9')) c = getchar();
	if (c == '-') c = getchar(), d = 1;
	x = c - '0', c = getchar();
	while ('0' <= c && c <= '9') x = x * 10 + c - '0', c = getchar();
	if (d) x = - x;
}

void read(char & x)
{
	for (x = getchar(); 'A' > x || x > 'Z'; x = getchar());
}

struct da {int t; da * n;};
da das[maxn * 2], * adj = das, * edge[maxn];

void link(int x, int y)
{
	* (++ adj) = (da) {y, edge[x]}, edge[x] = adj;
	* (++ adj) = (da) {x, edge[y]}, edge[y] = adj;
}

int n, m, tot;
int a[maxn], w[maxn];
char order;

node * build(int l, int r)
{
	int t = (l + r) >> 1; node * p = to[a[t]];
	p->k = p->sum = p->maxi = w[a[t]];
	if (l < t) p->c[0] = build(l, t - 1), p->c[0]->f = p; else p->c[0] = null;
	if (t < r) p->c[1] = build(t + 1, r), p->c[1]->f = p; else p->c[1] = null;
	return update(p), p;
}

node * dfs(int u, int fa)
{
	da * e = edge[u]; a[++ tot] = u;
	while (e && e->t == fa) e = e->n;
	if (! e) return build(1, tot);
	node * p = dfs(e->t, u);
	for (e = e->n; e; e = e->n)
		if (e->t != fa) tot = 0, dfs(e->t, u)->f = to[u];
	return p;
}

int main()
{
	freopen("1036.in", "r", stdin);
	freopen("1036.out", "w", stdout);
	
	int i, j, k; node * p; pair <int, int> res; read(n);
	for (i = 1; i < n; ++ i) read(j), read(k), link(j, k);
	for (i = 1; i <= n; ++ i) read(w[i]), to[i] = null + i, to[i]->hehe = i;
	dfs(1, 1)->f = null;
	for (read(m); m --; )
		{
			read(order);
			if (order == 'C')
				{
					read(j), read(k), p = to[j];
					splay(p), p->k = k, update(p);
					continue;
				}
			read(order), read(j), read(k);
			access(to[j]), res = access(to[k]);
			if (order == 'S') printf("%d\n", res.first);
			else printf("%d\n", res.second);
		}

	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值