近期学习内容

1.Spaly的启发式合并
2.点分治算法
3.线段树合并
4.树链剖分

/*
一开始每一个节点都是一棵Splay。
对于一个节点u,我们将子节点v都启发式合并到节点u上,
并将v这棵Splay权值整体加上w,然后统计两棵Spaly的节点所形成的答案,
即对于v中的每一个节点,查询 pre(K - tr[x].v) 的个数 
*/
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 2e5 + 10, INF = 0x3f3f3f;

struct Tree {
	int p, v, s[2], siz;
	int tag;
	void init(int _v) {
		siz = 1;
		v = _v;
	}
} tr[N]; 
struct Edge {
	int v, w, nxt;
} e[N << 1];

int fa[N], n, m, head[N], cnt, idx, root[N], siz[N], num[N];

void pushup(int u) 
{
	tr[u].siz = tr[tr[u].s[0]].siz + tr[tr[u].s[1]].siz + 1;
}
void pushdown(int u) 
{
	if( tr[u].tag) {
		Tree & l = tr[tr[u].s[0]], & r = tr[tr[u].s[1]];
		l.tag += tr[u].tag, l.v += tr[u].tag;
		r.tag += tr[u].tag, r.v += tr[u].tag;
		tr[u].tag = 0;
	} 
}

void AddEdge(int u, int v, int w) 
{
	e[ ++cnt].v = v;
	e[cnt].w = w;
	e[cnt].nxt = head[u];
	head[u] = cnt; 
}

bool dir(int x) {
	return tr[tr[x].p].s[1] == x;
}

void con(int x, int y, int son) 
{
	tr[y].s[son] = x, tr[x].p = y; 
} 

void rotate(int x) 
{
	int y = tr[x].p, ys = dir(x);
	int z = tr[y].p, zs = dir(y);
	int B = tr[x].s[ys ^ 1];
	con(B, y, ys), con(y, x, ys ^ 1), con(x, z, zs); 
} 

void splay(int i, int x, int k) 
{
	while(tr[x].p != k) {
		int y = tr[x].p;
		if( tr[y].p != k)
			rotate(dir(x) == dir(y) ? y : x);
		rotate(x);
	}
	if( !k)	root[i] = x;
}

int get_root(int x) 
{
	return fa[x] == x ? x : get_root(fa[x]); 
}

void insert(int i, int v) 
{
	int u = root[i], p = 0;
	while(u)	p = u, u = tr[u].s[v > tr[u].v];
	u = ++ idx;
	tr[u].init(v);
	con(u, p, v > tr[p].v);
	splay(i, u, 0);
}

int get_pre(int i, int v) {
	int u = root[i], p = 0;
	while(u) {
		pushdown(u);
		if( v >= tr[u].v)
			p = u, u = tr[u].s[1];
		else u = tr[u].s[0];
	} 
	if(!p)	return INF;
	splay(p, 0, i);
	return tr[tr[p].s[0]].siz + 1;
} 

void dfs2(int rt, int u)//将u合并到rt上 
{
	pushdown(u);
	if( tr[u].s[0])		dfs2(rt, tr[u].s[0]);
	if( tr[u].s[1]) 	dfs2(rt, tr[u].s[1]);
	insert(root[rt], tr[u].v);
	num[rt] += get_pre(rt, m - tr[u].v);
}

int dfs1(int u, int p) 
{
	int rt = u;
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].v;
		if( v == p)		continue;
		int t = dfs1(v, u);//返回合并后并查集的树根 
		tr[root[t]].tag += e[i].w;
		tr[root[t]].v += e[i].w;
		rt = get_root(u);
		if( siz[rt] < siz[t])	swap(rt, t);
		fa[t] = rt;
		siz[rt] += siz[t];
		num[rt] += num[t];
		dfs2(rt, root[t]);
	}
	return rt;
}

int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) {
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		AddEdge(u, v, w), AddEdge(v, u, w);
		fa[i] = i, siz[i] = 1; 
		
	}
	for(int i = 1; i <= n; i ++) {
		root[i] = i;
		tr[i].init(v);
	}
	scanf("%d", &m);
	idx = n;
	dfs1(1, 0); 
	printf("%d
", num[get_root(1)]);
	return 0; 
}
原文地址:https://www.cnblogs.com/wyy0804/p/13751077.html