线段树合并优化建图

关于正确性的感性理解

在x和y有一个为空时,可以直接返回那个不为空的。这样做不会导致给一些节点加一些不该加的边的原因可以这么理解:当你想给某个节点添加一个儿子的时候,必然是两颗树节点都有这个节点,那么此时代码便会新建一个节点,故这样的merge不会导致连出不该连的边。

实现细节

这两种写法都是正确的:
使用主席树的插入方法,无论如何都新建节点。那么此时插入操作的执行位置无影响。

void ins(int &u, int l, int r, int x, int p) {
    int tmp = u; u = ++tcnt, t[u] = t[tmp];
    if(l == r) {
        if(tmp) adde(u+n, tmp+n, MAXN);
        adde(u+n, p, MAXN);
        return ;
    }
    if(x <= mid) ins(t[u].ls, l, mid, x, p); 
    else ins(t[u].rs, mid+1, r, x, p);
}
int merge(int x, int y, int l, int r) {
	if(!x || !y) return x + y;
	int u = ++tcnt;
	if(l == r) {
		adde(u+n, x+n, INF), adde(u+n, y+n, INF);
		return u;
	}
	if(t[x].ls || t[y].ls) t[u].ls = merge(t[x].ls, t[y].ls, l, mid);
	if(t[x].rs || t[y].rs) t[u].rs = merge(t[x].rs, t[y].rs, mid+1, r);
	return u;
}
void dfs(int u) {
    size[u] = 1;
    for(ri i = 0; i < adj[u].size(); ++i) {
        dfs(adj[u][i]), root[u] = merge(root[u], root[adj[u][i]], 1, MAXN);
    }
    ins(root[u], 1, MAXN, val[u], u);
}

插入采用权值线段树插入,仅节点为空时新建。这样则需要保证插入操作在合并操作之前,否则会导致如果一个父节点直接等同于一个子节点,那么在插入父节点的时候,子节点也会被插入。
但其实没啥必要判断空节点,毕竟每次都是直接插入空树。

void ins(int &u, int l, int r, int x, int p) {
    //if(!u) u = ++tcnt;
    u = ++tcnt;
    if(l == r) { 
        adde(u+n, p, MAXN);
        return ;
    }
    if(x <= mid) ins(t[u].ls, l, mid, x, p); 
    else ins(t[u].rs, mid+1, r, x, p);
}
int merge(int x, int y, int l, int r) {
	if(!x || !y) return x + y;
	int u = ++tcnt;
	if(l == r) {
		adde(u+n, x+n, INF), adde(u+n, y+n, INF);
		return u;
	}
	if(t[x].ls || t[y].ls) t[u].ls = merge(t[x].ls, t[y].ls, l, mid);
	if(t[x].rs || t[y].rs) t[u].rs = merge(t[x].rs, t[y].rs, mid+1, r);
	return u;
}
void dfs(int u) {
    size[u] = 1;
    ins(root[u], 1, MAXN, val[u], u);
    for(ri i = 0; i < adj[u].size(); ++i) {
        dfs(adj[u][i]), root[u] = merge(root[u], root[adj[u][i]], 1, MAXN);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值