[ABC347E] Set Add Query题解

思路

通过读题发现,每个数变化当且仅当这个数在集合内。所以不妨设它被添加进来的时间点为 \(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;
}
posted @ 2024-07-16 21:10  merlinkkk  阅读(37)  评论(0)    收藏  举报