模拟+数据结构:上海省选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  阅读(65)  评论(0)    收藏  举报