题解 灯
关于我在 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;
}