思路
通过读题发现,每个数变化当且仅当这个数在集合内。所以不妨设它被添加进来的时间点为 \(L_i\),它被删除的时间点为 \(R_i\),所以它被增加的数量就是这段时间内集合数量之和。所以用一个变量 \(cnt\) 模拟当前集合内有多少个数,前缀和维护即可。具体实现参见代码。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200010];
int sum[200010];
unordered_map<int,int> mp;// map判重
int ans[200010];
int p[200010];// 每个数出现的位置, 相当于 L_i
signed main() {
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++) cin>>a[i];
int cnt=0;
for(int i=1;i<=n;i++) p[i]=1;
for(int i=1;i<=m;i++) {
if(mp[a[i]]==1) {// 重复了
ans[a[i]]+=sum[i-1]-sum[p[a[i]]-1];
cnt--;
mp[a[i]]=0;
p[a[i]]=i;
}
else { // 没有重复
cnt++;
mp[a[i]]=1;
p[a[i]]=i;
}
sum[i]=cnt;
sum[i]=sum[i-1]+sum[i];
//cout<<sum[i]<<" ";
}
//cout<<sum[4]<<"\n";
for(int j=1;j<=n;j++) {
int i=m+1;
a[i]=j;
if(mp[a[i]]==1) {
ans[a[i]]+=sum[m]-sum[p[a[i]]-1];
//cout<<m<<" "<<p[i]-1<<"\n";
cnt--;
mp[a[i]]=0;
}
else {
cnt++;
mp[a[i]]=1;
}
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
return 0;
}
标签:cnt,int,题解,Add,long,200010,ABC347E,Query
From: https://www.cnblogs.com/merlinkkk/p/18306127