P3998 [SHOI2013] 发微博
P3998 [SHOI2013] 发微博
题目翻译:
题目描述已经较为详细,这就不翻译了。
思路:
考虑暴力: 我们可以给每个人都添加一个关系链,每发出一次一条消息,就将所有与他有关系的答案依次加一。这样就统计出来了。但是这样的复杂度为 \(O(mn)\) 无法过。
考虑优化: 我们发现 \(m\) 次询问时难以优化掉的。考虑如何把 \(n\) 优化掉。我们发现暴力时每一次都要给所有人加一,那有什么办法可以不用每次都修改了?可以考虑前缀和。我们发现某一段有关系的区间内所加的消息数是等于,它那个人结束时发出的所有消息数,减去刚建立关系时的消息数,那我们只需要维护每个人发出消息数,在有人加入时,和退出时,分别减去和加上即可。
注意: 由于不一定所有人最后都会取消关系,所以我们最后要强制取消所有关系,那我们可以用 \(set\) 维护所有有关系的人,由于 \(set\) 操作都是 \(O(\log n)\) 的,所以最终复杂度为 \(O(m \log n)\)
完整代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,cnt[N],ans[N];
set<int>s[N];
set<int>::iterator it;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;++i){
char opt;
cin>>opt;
if(opt=='!'){
int x;
cin>>x;
cnt[x]++;
}
if(opt=='+'){
int x,y;
cin>>x>>y;
ans[x]-=cnt[y];
ans[y]-=cnt[x];
s[x].insert(y);
s[y].insert(x);
}
if(opt=='-'){
int x,y;
cin>>x>>y;
ans[x]+=cnt[y];
ans[y]+=cnt[x];
s[x].erase(y);
s[y].erase(x);
}
}
for(int i=1;i<=n;++i){
for(it=s[i].begin();it!=s[i].end();++it){
ans[i]+=cnt[*it];
}
}
for(int i=1;i<=n;++i)cout<<ans[i]<<" ";
return 0;
}
本文作者:XichenOC
本文链接:https://www.cnblogs.com/XichenOC/p/18689011
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步