1 条题解

  • 0
    @ 2025-8-24 21:55:22

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 午夜飘雪
    **

    搬运于2025-08-24 21:55:22,当前版本为作者最后更新于2017-12-14 19:38:27,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    考虑一个用户x发微博的时候,他会对所有x当前的好友y产生一点答案贡献

    于是从xy成为好友,一直到xy解除好友关系,x对y产生的总贡献一共是(解除好友关系时x的微博数-成为好友时x的微博数)

    那么我们记录一个cnt[x],表示到目前为止x共发了多少条微博

    对于每个点建立一个set记录x的当前好友集合

    每次加(减)点的同时,把ans[x]减去(加上)cnt[y](有点像差分?)

    但是因为只有在解除好友的时候贡献才会被完整统计,所以最后要手动解除所有人的好友关系,即遍历一遍每个人的set

    时间复杂度O(mlogn),具体实现见代码

        #include<iostream>
        #include<cstdio>
        #include<set>
        using namespace std;
        const int N=200009;
        int n,m,cnt[N],ans[N];
        set<int>s[N];
        set<int>::iterator it;
        int main(){
            ios::sync_with_stdio(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;
        }
    

    做完之后一想,总觉得这个set大材小用了,能不能不用啊

    于是……开始考虑这个set到底起了什么作用

    归根结底就是因为最后需要手动解除一遍所有人的好友关系,才需要用set来维护每个人的好友集合,这样可以知道每个人剩下的好友都是谁

    那么能不能让他们到最后所有人都没有好友关系呢?

    反着处理所有操作就可以啦,因为一开始所有人都没有好友关系

        #include<iostream>
        #include<cstdio>
        using namespace std;
        const int N=200009,M=500009;
        int n,m,data[M][2],cnt[N],ans[N];
        char opt[M];
        int main(){
            ios::sync_with_stdio(0);
            cin>>n>>m;
            for(int i=1;i<=m;++i){
                cin>>opt[i];
                if(opt[i]=='!')cin>>data[i][0];
                if(opt[i]=='+')cin>>data[i][0]>>data[i][1];
                if(opt[i]=='-')cin>>data[i][0]>>data[i][1];
            }
            for(int i=m;i;--i){
                if(opt[i]=='!')++cnt[data[i][0]];
                if(opt[i]=='+'){
                    ans[data[i][0]]+=cnt[data[i][1]];ans[data[i][1]]+=cnt[data[i][0]];
                }
                if(opt[i]=='-'){
                    ans[data[i][0]]-=cnt[data[i][1]];ans[data[i][1]]-=cnt[data[i][0]];
                }
            }
            for(int i=1;i<=n;++i)cout<<ans[i]<<" ";
            return 0;
        }
    

    这样只用O(m)就解决了问题 虽然mlogn就能过

    顺手安利一发博客

    • 1

    信息

    ID
    2949
    时间
    1000ms
    内存
    250MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者