模拟+数据结构:上海省选2013 P3998题解

P3998 [SHOI2013] 发微博

01.题意理解

进行$m$次操作,操作分为$3$种:

\(01.发布一条说说\)

\(02.和另一个用户建立朋友关系\)

\(03.和另一个用户解除朋友关系\)

求$n$个人最后各自可以看见多少条说说

02.思路分析

思路1$(10pts)$:

对于$n≤1000且m≤1000$ 思路显然:

输入$m$次操作

01.操作为$2$时:每次输入$a,b$并建边$[a,b]$

02.操作为$3$时:删边$[a,b]$

03.操作为$1$时:输入$a$,将所有与$a$相连的点看见的说说数量$ans[i]$加1

最后输出$ans[1$~$n]$即可,复杂度$O(mn)$

思路2:\((100pts)\)

对于$n≤30000且m≤30000$ 考虑降低时间复杂度

$O(m)$是难以被降低的,故考虑将$O(mn)$降为$O(m)$

那么就可以形成新的思路:

前置:

建立一个二维$vector$数组$edge$,定义$edge[Node1][i]$表示$Node1$结点所连接的一个节点

那么我们可以用一些常用的数组操作来记录每个节点在$edge[x]$中的位置$id$

同时可以建立$d$数组来存储每个点已经发送的信息数量

显然我们可以$O(1)$时间完成对任意边的查询

则有:

01.操作$2$时:建边$[a,b]$,在$edge[a]$中push_back此时的$d[a]$,存储$id[a][b]$

注意:$vector$内存储的时$d[a]$而非$b$

02.操作$3$时:删边$[a,b]$,将$ans[b]$存储为$d[a]-edge[a]$

03.操作$1$时:将$d[a]++$

注意: 操作完成后可能仍有边未删除,此时需要额外进行删边操作

#include<bits/stdc++.h>
#define int long long
const int MAXN=2e5+10;
using namespace std;

struct E
{
    int u,v;
};
E arr[MAXN];
vector<int> edge[MAXN];
unordered_map<int,unordered_map<int,bool> > vis;
unordered_map<int,unordered_map<int,int> > id,id2;
int d[MAXN],ans[MAXN];

signed main()
{
     ios::sync_with_stdio(0);
     cin.tie(0),cout.tie(0);

    int n,m,cnt=0;
    cin>>n>>m;

    while(m--)
    {
//    	cout<<"TTT"<<"\n";
        char opt;
        cin>>opt;

        if(opt=='!')
        {
            int u;
            cin>>u;
            ++d[u];
        }
        else if(opt=='+')//建边 
        {
            int u,v;
            cin>>u>>v;
//			cout<<"2\n";
            if(vis[u][v]==0)
            {
            	
                //记录v在u中的位置 
                id[u][v]=edge[u].size();
                id[v][u]=edge[v].size();

                //建图 
                edge[u].push_back(d[u]);
                edge[v].push_back(d[v]);
                
                vis[u][v]=vis[v][u]=1;

                int u2=min(u,v);
                int v2=max(u,v);

//                id2[u2][v2]=arr.size();
                arr[++cnt]={u2,v2};
            }
        }
        else//删边
        {
            int u,v;
            cin>>u>>v;
            if(vis[u][v]==1)
            {
                int sd=edge[u][id[u][v]];
                ans[v]+=d[u]-sd;
                
                sd=edge[v][id[v][u]];
                ans[u]+=d[v]-sd;

                vis[u][v]=vis[v][u]=0;

                int u2=min(u,v);
                int v2=max(u,v);
				
            }
        }
    }

//    cout<<"1\n";

    
    for(int i=1;i<=cnt;++i)
    {
    	int u=arr[i].u,v=arr[i].v;
    	if(vis[u][v])
    	{
    		int sd=edge[u][id[u][v]];
	        ans[v]+=d[u]-sd;
	                
	        sd=edge[v][id[v][u]];
	        ans[u]+=d[v]-sd;
	        vis[u][v]=vis[v][u]=0;
	    }
	}


    for(int i=1;i<=n;++i)
        cout<<ans[i]<<" ";
    
}
posted @ 2025-04-13 10:11  SamXia  阅读(85)  评论(0)    收藏  举报