2 条题解

  • 0
    @ 2025-9-15 16:31:41

    在这里提供一个数据结构做法,当然不是特别傻的双 loglog 树剖。

    因为赛时时间十分紧张,所以我想到单 loglog 就没有多想,直接开始写,然后写完调都没调直接一遍过,感觉无论是思维难度,还是代码难度都是非常简单的。

    我们考虑以 dfndfn 序列建立标记永久化线段树。因为一个点能影响到的一定是它的子树,于是在 dfndfn 序列上对应了一个区间 ,我们把这个区间打上标记

    查询的时候我们考虑线段树上所有经过的点都要对深度取 maxmax

    然后就做完了

    • 0
      @ 2025-9-12 17:25:27
      #include <bits/stdc++.h>  
      using namespace std;
      const int N=1e5+5;
      int to[N<<1],nxt[N<<1],head[N],fa[N],boss[N],built[N],ans[N],idx[N],opt[N],tot;
      void add(int u,int v)
      {
          to[++tot]=v,nxt[tot]=head[u],head[u]=tot;
      }
      void dfs(int x)
      {
          for(int i=head[x];i;i=nxt[i])
      		if(to[i]!=fa[x])
      			fa[to[i]]=x,dfs(to[i]);
      }
      int find(int x)
      {
          return (boss[x]==x)?x:(boss[x]=find(boss[x]));
      }
      int main()
      {
      	int n,m;
          scanf("%d%d",&n,&m);
          int u,v;
          for(int i=1;i<n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
          dfs(1);
          built[1]=1;//重建次数 
          for(int i=1;i<=m;i++)
          {
              scanf("%d%d",&opt[i],&idx[i]);
              if(opt[i]==0) built[idx[i]]++;
          }
          for(int i=1;i<=n;i++) boss[i]=(built[i])?i:fa[i];//并查集初始化:重建过,指向自己;没重建过,指向父亲 
          for(int i=m;i>=1;i--) // 倒序 
          {
              if(opt[i]==0)
              {
                  built[idx[i]]--;//重建次数减一,删除一次标记
                  if(!built[idx[i]]) boss[idx[i]]=fa[idx[i]];// 没重建过,指向自己的父亲 
              }
              else ans[i]=find(idx[i]);
          }
          for(int i=1;i<=m;i++) if(opt[i]==1) printf("%d\n",ans[i]);
          return 0;
      }
      
      • 1

      信息

      ID
      393
      时间
      1000ms
      内存
      256MiB
      难度
      5
      标签
      (无)
      递交数
      38
      已通过
      16
      上传者