51nod 1297 管理二叉树 (树分治)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <vector>
#include <set>
#include <assert.h>
using namespace std;


#define N 200020
#define M 500200
#define inf 0x3f3f3f3f
#define mod 110119
#define LL long long
#define ls (i << 1)
#define rs (ls | 1)
#define md (ll + rr >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define MP make_pair
#define pii pair<int, int>
#define ui unsigned int
#define fi first
#define se second
#define pll pair<LL, LL>

int n, a[N];
int fa[N];
int fst[N], nxt[M], vv[M], e;

int dep[N], sz[N], mx[N];
int q[N], qh, qt;
bool vis[N], tvis[N];
LL sum[N * 20];
int cnt[N * 20];
int bk_cnt;

struct node {
	int x, y, d;
	node() {}
	node(int x, int y, int d):x(x), y(y), d(d) {}
};
vector<node> vt[N];

void init() {
	memset(fst, -1, sizeof fst);
	e = 0;
}
void add(int u, int v) {
	vv[e] = v, nxt[e] = fst[u], fst[u] = e++;
}

struct bst {
	int tag[N << 2];
	
	int x[N], y[N], xx[N], yy[N];

	void push_down(int i) {
		if(tag[i]) {
			tag[ls] = tag[rs] = tag[i];
			tag[i] = 0;
		}
	}
	void update(int l, int r, int v, int ll, int rr, int i) {
		if(ll == l && rr == r) {
			tag[i] = v;
			return;
		}
		push_down(i);
		if(r <= md) update(l, r, v, lson);
		else if(l > md) update(l, r, v,rson);
		else update(l, md, v, lson), update(md + 1, r, v, rson);
	}
	int query(int x, int ll, int rr, int i) {
		if(tag[i]) return tag[i];
		if(ll == rr) return 0;
		if(x <= md) return query(x, lson);
		return query(x, rson);
	}

	void insert(int v) {
		if(v == 1) {
			x[1] = 1, y[1] = n;
		}
		else {
			int p = query(a[v], 1, n, 1);
			if(a[v] < a[p]) {
				x[v] = x[p], y[v] = y[p];
			}
			else 
				x[v] = xx[p], y[v] = yy[p];
			fa[v] = p;
		}
		yy[v] = y[v];
		y[v] = a[v] - 1;
		xx[v] = a[v] + 1;
		if(x[v] <= y[v]) update(x[v], y[v], v, 1, n, 1);
		if(xx[v] <= yy[v]) update(xx[v], yy[v], v, 1, n, 1);
	}


}BST;


void bfs(int s) {
	
	qh = qt = 0;
	q[qt++] = s;
	tvis[s] = 1;
	dep[s] = 0;

	while(qh < qt) {
		int u = q[qh++];
		for(int i = fst[u]; ~i; i = nxt[i]) {
			int v = vv[i];
			if(vis[v] || tvis[v]) continue;
			tvis[v] = 1;
			dep[v] = dep[u] + 1;
			q[qt++] = v;
		}
	}
	for(int i = 0; i < qt; ++i) tvis[q[i]] = 0;

}

void divide(int s) {
	bfs(s);
	int rt = 0, tmp = inf;
	for(int i = qt - 1; i >= 0; --i) {
		int u = q[i];
		sz[u] = 1;
		mx[u] = 0;
		for(int j = fst[u]; ~j; j = nxt[j]) {
			int v = vv[j];
			if(dep[v] < dep[u] || vis[v]) continue;
			sz[u] += sz[v];
			mx[u] = max(mx[u], sz[v]);
		}
	}
	for(int i = 0; i < qt; ++i) {
		int u = q[i];
		mx[u] = max(mx[u], qt - sz[u]);
		if(mx[u] < tmp) tmp = mx[u], rt = u;
	}

	vis[rt] = 1;
	bfs(rt);
	int k = ++bk_cnt;
	vt[rt].push_back(node(k, -1, 0));
	for(int i = fst[rt]; ~i; i = nxt[i]) {
		int v = vv[i];
		if(vis[v]) continue;
		bfs(v);
		++bk_cnt;
		for(int j = 0; j < qt; ++j) {
			int u = q[j];
			vt[u].push_back(node(k, bk_cnt, dep[u] + 1));
		}
	}
	for(int i = fst[rt]; ~i; i = nxt[i]) {
		int v = vv[i];
		if(!vis[v]) divide(v);
	}


}
LL query(int u) {
	LL ret = 0;
	for(int i = 0; i < vt[u].size(); ++i) {
		int x = vt[u][i].x;
		int y = vt[u][i].y;
		int d = vt[u][i].d;
		ret += 1LL * cnt[x] * d + sum[x];
		if(y != -1) ret -= 1LL * cnt[y] * d + sum[y];
	}
	return ret;
}

void upd(int u) {
	for(int i = 0; i < vt[u].size(); ++i) {
		int x = vt[u][i].x;
		int y = vt[u][i].y;
		int d = vt[u][i].d;
		sum[x] += d;
		cnt[x] ++;
		if(y != -1) cnt[y] ++, sum[y] += d;
	}
}

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
	}
	for(int i = 1; i <= n; ++i) {
		BST.insert(i);
	}
	init();
	for(int i = 2; i <= n; ++i) {
		add(fa[i], i);
		add(i, fa[i]);
	}
	memset(vis, 0, sizeof vis);
	bk_cnt = 0;

	divide(1);
	LL ans = 0;
	for(int i = 1; i <= n; ++i) {
		if(i > 1) {
			ans += query(i);
		}
		upd(i);
		printf("%lld\n", ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值