2 条题解

  • 0
    @ 2026-5-8 21:26:19

    首先离线处理。

    然后你就会发现这题的 A 操作的作用仅限于告诉你 R 操作删除了哪条边,然后离线处理时加上即可。

    答案部分搜索一下就行了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+10;
    int v[N],v1[N],f[N],op[N],ans[N];
    struct node{int x,y;}e[N];
    vector<int>G[N];
    void dfs(int x,int vv)
    {
    	ans[x]=max(ans[x],vv);
    	for(int y:G[x])if(!ans[y])dfs(y,vv);
    }
    signed main()
    {
    	int n,q;cin>>n>>q;
    	vector<node>vec;
    	for(int i=1;i<=q;i++)
    	{
    		string s;cin>>s;
    		if(s[0]=='D')
    			op[i]=1,cin>>e[i].x;
    		if(s[0]=='A')
    			op[i]=2,cin>>e[i].x>>e[i].y,
    			vec.push_back({e[i].x,e[i].y});
    		if(s[0]=='R')
    			op[i]=3,cin>>e[i].x;
    	}
    	for(int i=1;i<=n;i++)v[i]=1;
    	for(int i=1;i<=vec.size();i++)v1[i]=1;
    	for(int i=1;i<=q;i++)
    	{
    		if(op[i]==1)v[e[i].x]=0;
    		if(op[i]==3)v1[e[i].x]=0;
    	}
    	for(int i=1;i<=vec.size();i++)if(v1[i])
    		G[vec[i-1].x].push_back(vec[i-1].y),
    		G[vec[i-1].y].push_back(vec[i-1].x);
    	for(int i=1;i<=n;i++)if(v[i])dfs(i,q);
    	for(int i=q;i>=1;i--)
    	{
    		if(op[i]==1)
    		{
    			int x=e[i].x;if(ans[x])continue;
    			dfs(x,i-1);
    		}
    		if(op[i]==3)
    		{
    			int x=vec[e[i].x-1].x,y=vec[e[i].x-1].y;
    			G[x].push_back(y);
    			G[y].push_back(x);
    			if(ans[x]==0&&ans[y]==0)continue;
    			dfs(x,i-1);dfs(y,i-1);
    		}
    	}
    	for(int i=1;i<=n;i++)cout<<ans[i]<<'\n';
    	return 0;
    }
    • 0
      @ 2026-5-5 17:08:51

      鉴定为语文阅读题。

      注意到操作 A x y 一定是链接两个活跃农场这启示了我们几点。

      首先一个点肯定不会在停产之后进行 A 操作。

      进一步地,一个点变得无关,只可能是经历了 D x 操作且断掉了所有与活跃农场的边的路径,而且变得无关就不会建边,所以一个农场的有关的时间是一个形如 [1,agex][1,age_x] 的东西。

      同时我们发现建边之前两个端点都是活跃的,所以这条边的建立时间不会对答案产生影响,但是删除是会的,我们可以记录它的删除时间 rir_i

      其实这里做法就可以分成两种了,一种是倒过来,删点变成加点,删边变成加边们可以用并查集。

      我的做法复杂一点,我们发现题目中所有输出的最大值一定是最大的 agexage_x,而每个点的输出值也不会小于 agexage_x,我们将 agexage_x 初始化答案 ansxans_x

      接下来,我们用优先队列维护,每个点只取一次,每次取出一个最大值的点尝试更新相连的点。

      只要我还有关,我们的边还在,你就还是有关的,所以我们更新点的方式也就是尝试 ansy=min(ansx,r(x,y))ans_y=\min(ans_x,r_{(x,y)})

      我们就这样一直更新就行了,时间复杂度是 O(nlogn)O(n\log n),没有并查集做法那么优秀。

      但是好写好理解!

      #include<bits/stdc++.h>
      #define LL long long
      #define val first
      #define num second
      using namespace std;
      const LL N=2e5+5;
      LL n,q,ans[N],x,y,cnt,e[N][2],r[N],vis[N],age[N];
      char c[15];
      vector<pair<LL,LL> >v[N];
      priority_queue<pair<LL,LL> >p;
      int main()
      {
      	scanf("%lld%lld",&n,&q);
      	for(int i=1;i<=N;i++)
      	{
      		age[i]=-1,r[i]=-1;
      	}
      	for(int Q=1;Q<=q;Q++)
      	{
      		scanf("%s",c);
      		if(c[0]=='D')
      		{
      			scanf("%lld",&x);
      			if(age[x]==-1)age[x]=Q-1;
      		}
      		if(c[0]=='A')
      		{
      			scanf("%lld%lld",&x,&y);
      			++cnt;
      			v[x].push_back({y,cnt});
      			v[y].push_back({x,cnt});
      		}
      		if(c[0]=='R')
      		{
      			scanf("%lld",&x);	
      			r[x]=Q-1;
      		}
      	}
      	for(int i=1;i<=cnt;i++)
      	{
      		if(r[i]==-1)r[i]=q;
      	}
      	for(int i=1;i<=n;i++)
      	{
      		if(age[i]==-1)age[i]=q;
      	}
      	for(int i=1;i<=n;i++)
      	{	
      		ans[i]=age[i];
      		p.push({ans[i],i});
      	}
      	while(!p.empty())
      	{
      		LL t=p.top().num;
      		p.pop();
      		if(vis[t])continue;
      		vis[t]=1;
      		for(pair<LL,LL> i:v[t])
      		{
      			if(ans[i.val]<min(ans[t],r[i.num]))
      			{
      				ans[i.val]=min(ans[t],r[i.num]);
      				p.push({ans[i.val],i.val});
      			}
      		}
      	}
      	for(int i=1;i<=n;i++)
      	{
      		printf("%lld\n",ans[i]);
      	}
      	return 0;
      }
      
      • 1

      信息

      ID
      7660
      时间
      1000ms
      内存
      128MiB
      难度
      8
      标签
      递交数
      17
      已通过
      6
      上传者