异象石——最近公共祖先

题目链接:

https://www.acwing.com/problem/content/357/

题意:

  给出一个树上节点的集合,动态加入或者删除节点,询问连通所有节点的最小边集的权值之和。

解法:

  把集合中的节点按照时间戳排序,每相邻两个节点距离以及首尾节点距离累加,累加之和为答案的两倍。(目前不会证明)

节点排序用set维护,首先加入0和inf,以便修改。

代码:

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int N=100000+5;
  5 const int INF=N-1;
  6 
  7 int n,m;
  8 
  9 int head[N],ver[2*N],edge[2*N],nex[2*N],tot=1;
 10 inline void add(int x,int y,int z)
 11 {
 12     ver[++tot]=y;
 13     edge[tot]=z;
 14     nex[tot]=head[x];
 15     head[x]=tot;
 16 }
 17 
 18 int d[N],f[N][20],max_t;
 19 ll dis[N];
 20 void bfs()
 21 {
 22     max_t=log(n)/log(2)+1;
 23     d[1]=1;
 24     dis[1]=0;
 25     queue<int> q;
 26     q.push(1);
 27     while(!q.empty())
 28     {
 29         int x=q.front();
 30         q.pop();
 31         for(int i=head[x];i;i=nex[i])
 32         {
 33             int y=ver[i];
 34             if(d[y])continue;
 35             d[y]=d[x]+1;
 36             dis[y]=dis[x]+edge[i];
 37             f[y][0]=x;
 38             for(int i=1;i<=max_t;++i)
 39                 f[y][i]=f[f[y][i-1]][i-1];
 40             q.push(y);
 41         }
 42     }
 43 }
 44 int lca(int x,int y)
 45 {
 46     if(d[x]<d[y])swap(x,y);
 47     if(d[x]>d[y])
 48         for(int i=max_t;i>=0;--i)
 49             if(d[f[x][i]]>=d[y])
 50                 x=f[x][i];
 51     if(x==y)return x;
 52     for(int i=max_t;i>=0;--i)
 53         if(f[x][i]!=f[y][i])
 54             x=f[x][i],y=f[y][i];
 55     return f[x][0];
 56 }
 57 
 58 int dfn[N],to_node[N],tot2=0;
 59 void dfs(int x)
 60 {
 61     dfn[x]=++tot2;
 62     to_node[tot2]=x;
 63     for(int i=head[x];i;i=nex[i])
 64     {
 65         int y=ver[i];
 66         if(dfn[y])continue;
 67         dfs(y);
 68     }
 69 }
 70 
 71 inline ll dist(int x,int y)
 72 {
 73     if(x==0||y==0)
 74         return 0;
 75     return dis[x]+dis[y]-2*dis[lca(x,y)];
 76 }
 77 
 78 int main()
 79 {
 80     scanf("%d",&n);
 81     for(int i=1;i<n;++i)
 82     {
 83         int x,y,z;
 84         scanf("%d%d%d",&x,&y,&z);
 85         add(x,y,z);
 86         add(y,x,z);
 87     }
 88     bfs();
 89     dfs(1);
 90     scanf("%d",&m);
 91     char op;
 92     ll ans=0;
 93     set<int> s;
 94     s.insert(0);
 95     s.insert(INF);
 96     for(int i=0;i<m;++i)
 97     {
 98         scanf(" %c",&op);
 99         if(op=='+')
100         {
101             int x;
102             scanf("%d",&x);
103             auto r=s.insert(dfn[x]);
104             auto it=r.first,it1=it,it2=it;
105             --it1;++it2;
106             ans-=dist(to_node[*it1],to_node[*it2]);
107             ans+=dist(to_node[*it1],to_node[*it]);
108             ans+=dist(to_node[*it2],to_node[*it]);
109         }
110         else if(op=='-')
111         {
112             int x;
113             scanf("%d",&x);
114             auto it=s.find(dfn[x]),it1=it,it2=it;
115             --it1;++it2;
116             ans+=dist(to_node[*it1],to_node[*it2]);
117             ans-=dist(to_node[*it1],to_node[*it]);
118             ans-=dist(to_node[*it2],to_node[*it]);
119             s.erase(it);
120         }
121         else
122         {
123             auto it1=s.begin();
124             auto it2=s.rbegin();
125             ++it1;++it2;
126             printf("%lld\n",(ans+dist(to_node[*it1],to_node[*it2]))/2);
127         }
128     }
129     return 0;
130 }
View Code

猜你喜欢

转载自www.cnblogs.com/judp/p/11230863.html