CF1051G Distinctification

CF1051G Distinctification

显然,最后的 aa 集合是唯一的。

aia_i 两两不同,则有多个 aia_i 连续的值域段,段内满足 bib_i 递减最优。

否则,将 aia_i 平铺往后,与后面的值域段合并即可,并查集维护。

考虑计算答案,发现其只与最终结果相关,为 (aiai)×bi\sum (a'_i-a_i)\times b_i,线段树维护值域块答案即可。

时间复杂度 O(nlogn)\mathcal O(n\log n)

#include <bits/stdc++.h>

using namespace std;

//#define int long long
typedef long long ll;
#define ha putchar(' ')
#define he putchar('\n')

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

inline void write(ll x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9)
		write(x / 10);
	putchar(x % 10 + '0');
}

const int _ = 4e5 + 10;

int n, cnt, a[_], b[_], fa[_], rt[_];

bool vis[_];

ll s[_], ans;

struct Tr
{
	int siz, c[2];
	ll sum, val;
} t[_ * 30];

void pushup(int o)
{
	t[o].sum = t[t[o].c[0]].sum + t[t[o].c[1]].sum;
	t[o].siz = t[t[o].c[0]].siz + t[t[o].c[1]].siz;
	t[o].val = t[t[o].c[0]].val + t[t[o].c[1]].val + 1ll * t[t[o].c[0]].sum * t[t[o].c[1]].siz;
}

void upd(int &o, int l, int r, int p)
{
	if (!o)
		o = ++cnt;
	if (l == r)
	{
		t[o].sum = t[o].val = p;
		t[o].siz = 1;
		return;
	}
	int mid = (l + r) >> 1;
	if (p <= mid)
		upd(t[o].c[0], l, mid, p);
	else
		upd(t[o].c[1], mid + 1, r, p);
	pushup(o);
}

ll qry(int x)
{
	return t[rt[x]].val + 1ll * (x - 1) * t[rt[x]].sum;
}

int merge(int x, int y)
{
	if (!x || !y)
		return x | y;
	int nw = x;
	t[nw].c[0] = merge(t[x].c[0], t[y].c[0]);
	t[nw].c[1] = merge(t[x].c[1], t[y].c[1]);
	if (!t[nw].c[0] && !t[nw].c[1])
	{
		t[nw].val = t[x].val + t[y].val + t[y].sum * t[x].siz;
		t[nw].sum = t[x].sum + t[y].sum;
		t[nw].siz = t[x].siz + t[y].siz;
	}
	else
		pushup(nw);
	return nw;
}

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

void link(int x, int y)
{
	x = find(x), y = find(y);
	fa[y] = x;
	ans -= qry(x) + qry(y);
	rt[x] = merge(rt[x], rt[y]);
	ans += qry(x);
}

signed main()
{
	n = read();
	for (int i = 1; i <= 4e5; ++i)
		fa[i] = i;
	for (int i = 1; i <= n; ++i)
	{
		a[i] = read(), b[i] = read();
		s[i] = s[i - 1] + 1ll * a[i] * b[i];
		a[i] = find(a[i]), fa[a[i]] = a[i] + 1;
		upd(rt[a[i]], 1, 4e5, b[i]);
	}
	for (int i = 1; i <= 4e5; ++i)
		fa[i] = i;
	for (int i = 1; i <= n; ++i)
	{
		ans += qry(a[i]);
		if (vis[a[i] + 1])
			link(a[i], a[i] + 1);
		if (vis[a[i] - 1])
			link(a[i] - 1, a[i]);
		vis[a[i]] = 1;
		write(ans - s[i]), he;
	}
	return 0;
}
posted @ 2022-08-01 21:53  蒟蒻orz  阅读(3)  评论(0编辑  收藏  举报  来源