• 近期学习内容


    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; 
    }
    
  • 相关阅读:
    动态规划-矩阵链乘法
    钢条切割问题
    代码着色
    Sublime配置C和C++编译运行环境
    Guava中集合类的简单实用
    Junit单元测试入门
    Sublime Text 快捷键
    Editplus 的配色方案
    利用Wireshark任意获取QQ好友IP实施精准定位
    linux下实现定时执行php脚本
  • 原文地址:https://www.cnblogs.com/wyy0804/p/13751077.html
Copyright © 2020-2023  润新知