题解 灯

传送门

关于我在 NOI Online 开始前 3 分钟才看出这题做法,于是就没写完这件事

发现点数 \(>\sqrt n\) 的颜色数不超过 \(\sqrt n\)
发现 \(连续段数=点数-\sum\limits_i[i 及右边都点亮]\)
将点数较多的颜色称为 丰富的
那么丰富的颜色之间的边只有 \(O(\sqrt n*\sqrt n)\)
发现修改不丰富的颜色时可以暴力改
考虑 \((>\sqrt n, \leqslant \sqrt n)\) 的边
那么都在小的那个统计,
每个点在当前颜色熄灭前会给左,右边的颜色的修改带来 1 的加成
于是这样做就是 \(O(n\sqrt n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, q;
int edge[325][325];
bool lit[N], islarge[N];
vector<int> large, add[N], del[N], pos[N];
int col[N], cnt[N], que[N], nxt[N], buff[N], col_buc[N], sqr, psum, esum;

signed main()
{
	freopen("light.in", "r", stdin);
	freopen("light.out", "w", stdout);

	n=read(); m=read(); q=read(); sqr=sqrt(n);
	for (int i=1; i<=n; ++i) ++cnt[col[i]=read()];
	for (int i=1; i<=m; ++i) if (cnt[i]>sqr) large.pb(i), islarge[i]=1;
	for (int i=1; i<=q; ++i) que[i]=read();
	for (int i=1; i<=m; ++i) col_buc[i]=q+1;
	for (int i=q; i; --i) nxt[i]=col_buc[que[i]], col_buc[que[i]]=i;
	for (int i=2; i<=n; ++i) if (islarge[col[i-1]]&&islarge[col[i]]) {
		++edge[col[i-1]][col[i]];
		if (col[i]!=col[i-1]) ++edge[col[i]][col[i-1]];
	}
	for (int i=1; i<=n; ++i) if (!islarge[col[i]]) pos[col[i]].pb(i);
	// for (int i=1; i<=m; ++i) cout<<islarge[i]<<' '; cout<<endl;
	// for (int i=1; i<=q; ++i) cout<<nxt[i]<<' '; cout<<endl;
	for (int i=1; i<=q; ++i) {
		// cout<<"i: "<<i<<' '<<que[i]<<endl;
		// cout<<"lit: "; for (int j=1; j<=m; ++j) cout<<lit[j]<<' '; cout<<endl;
		// for (auto it:add[j]) ++buff[it];
		for (auto it:del[i]) --buff[it];
		// cout<<"buff: "<<buff[que[i]]<<endl;
		if (islarge[que[i]]) {
			if (lit[que[i]]) {
				psum-=cnt[que[i]]; esum-=buff[que[i]];
				for (auto& it:large) if (lit[it]) esum-=edge[que[i]][it];
				lit[que[i]]^=1;
			}
			else {
				lit[que[i]]^=1;
				psum+=cnt[que[i]]; esum+=buff[que[i]];
				for (auto& it:large) if (lit[it]) esum+=edge[que[i]][it];
			}
		}
		else {
			if (lit[que[i]]) {
				psum-=cnt[que[i]];
				for (auto& it:pos[que[i]]) if (lit[col[it-1]]) --esum;
				for (auto& it:pos[que[i]]) if (lit[col[it+1]] && col[it+1]!=col[it]) --esum;
				lit[que[i]]^=1;
			}
			else {
				lit[que[i]]^=1;
				psum+=cnt[que[i]];
				for (auto& it:pos[que[i]]) {
					if (lit[col[it-1]]) ++esum;
					if (islarge[col[it-1]]) ++buff[col[it-1]], del[nxt[i]].pb(col[it-1]);
					if (lit[col[it+1]] && col[it+1]!=que[i]) ++esum;
					if (islarge[col[it+1]]) ++buff[col[it+1]], del[nxt[i]].pb(col[it+1]);
				}
			}
		}
		// cout<<"esum: "<<esum<<endl;
		printf("%d\n", psum-esum);
	}

	return 0;
}
posted @ 2022-03-26 17:37  Administrator-09  阅读(1)  评论(0编辑  收藏  举报