CF1609F Interesting Sections

枚举最大值和最小值的 popcount,扫描线枚举右端点 rr,记 flf_l 表示 [l,r][l,r] 中最大值是否等于枚举的 popcount ++ [l,r][l,r] 中最小值是否为枚举的 popcount,单调栈维护 flf_l 的变化,那么答案即为 fl=2f_l=2ll 的个数,线段树维护即可。时间复杂度均摊 O(n(logn+logV))\mathcal O(n(\log n + \log V))

#include <bits/stdc++.h>

using namespace std;

namespace Fread
{
	const int SIZE = 1 << 23;
	char buf[SIZE], *S, *T;
	inline char getchar()
	{
		if (S == T)
		{
			T = (S = buf) + fread(buf, 1, SIZE, stdin);
			if (S == T)
				return '\n';
		}
		return *S++;
	}
}
namespace Fwrite
{
	const int SIZE = 1 << 23;
	char buf[SIZE], *S = buf, *T = buf + SIZE;
	inline void flush()
	{
		fwrite(buf, 1, S - buf, stdout);
		S = buf;
	}
	inline void putchar(char c)
	{
		*S++ = c;
		if (S == T)
			flush();
	}
	struct NTR
	{
		~NTR()
		{
			flush();
		}
	} ztr;
}

#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endif

typedef long long ll;

inline ll read()
{
	ll 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 * 10ll + c - '0', c = getchar();
	return x * f;
}

const int _ = 1e6 + 5, M = 62;

int n, t1 = 1, t2 = 1, stk1[_], stk2[_], c[_], cnt[M + 5];

struct abc
{
	int p, l, r, v;
};

vector<abc> k[_ + 5];

ll a[_], ans;

struct node
{
	int l, r, mx, mxc, lz;
} t[_ << 2];

void pushup(int o)
{
	t[o].mx = max(t[o << 1].mx, t[o << 1 | 1].mx);
	t[o].mxc = 0;
	if(t[o].mx == t[o << 1].mx) t[o].mxc += t[o << 1].mxc;
	if(t[o].mx == t[o << 1 | 1].mx) t[o].mxc += t[o << 1 | 1].mxc;
}

void build(int o, int l, int r)
{
	t[o].l = l, t[o].r = r, t[o].mx = t[o].lz = 0, t[o].mxc = r - l + 1;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(o << 1, l, mid), build(o << 1 | 1, mid + 1, r);
}

void tag(int o, int v)
{
	t[o].mx += v, t[o].lz += v;
}

void pushdown(int o)
{
	if(t[o].lz)
	{
		tag(o << 1, t[o].lz), tag(o << 1 | 1, t[o].lz), t[o].lz = 0;
	}
}

void update(int o, int l, int r, int v)
{
	if(l <= t[o].l && t[o].r <= r) return tag(o, v), void();
	pushdown(o);
	int mid = (t[o].l + t[o].r) >> 1;
//	if(r <= mid) update(o << 1, l, r, v);
//	else if(l > mid) update(o << 1 | 1, l, r, v);
//	else update(o << 1, l, mid, v), update(o << 1 | 1, mid + 1, r, v);
	if(l <= mid) update(o << 1, l, r, v);
	if(r > mid) update(o << 1 | 1, l, r, v);
	pushup(o);
}

signed main()
{
	n = read();
	for(int i = 1; i <= n; ++i)
	{
		a[i] = read(), c[i] = __builtin_popcountll(a[i]);
		cnt[c[i]]++;
	}
	for(int i = 1, p; i <= n; ++i)
	{
		while(t1 > 1 && a[stk1[t1]] > a[i])
		{
			p = stk1[t1--];
			k[c[p]].push_back({i, stk1[t1] + 1, p, -1});
		}
		k[c[i]].push_back({i, stk1[t1] + 1, i, 1});
		while(t2 > 1 && a[stk2[t2]] <= a[i])
		{
			p = stk2[t2--];
			k[c[p]].push_back({i, stk2[t2] + 1, p, -1});
		}
		k[c[i]].push_back({i, stk2[t2] + 1, i, 1});
		stk1[++t1] = i, stk2[++t2] = i;
	}
	for(int i = 0; i <= M; ++i)
	{
		if(!cnt[i]) continue;
		build(1, 1, n);
		for(int j = 1, cur = 0; j <= n; ++j)
		{
			while(cur < k[i].size() && k[i][cur].p <= j)
			{
				update(1, k[i][cur].l, k[i][cur].r, k[i][cur].v);
				cur++;
			}
			if(t[1].mx == 2) ans += t[1].mxc;
		}
	}
	printf("%lld\n", ans);
	return 0;
}
posted @ 2022-12-01 09:14  蒟蒻orz  阅读(6)  评论(0)    收藏  举报  来源