【CH#56C】异象石

这是一道毒瘤的LCA的题目。

我们对这棵树进行一次dfs,求出每一个点的时间戳,不难发现,我们按照时间戳排序,把异象石的节点排序,并且累加相邻两点的路径,最后的结果就是所求答案的两倍。

因此,我们采用STL中的set,按照时间戳递增的顺序维护异象石出现的序列,并用变量ans记录相邻两点的距离之和,那么答案就是ans/2.

设path(x,y)表示x,y之间的距离,d[x]表示x在树中的深度,那么存在path(x,y)=d[x]+d[y]-2*d[lca(x,y)],d数组可以通过dfs或bfs求出,lca可以通过倍增实现。

如果某一节点出现了异象石,那么我们根据这个节点的时间戳,把他放到set中的合适位置,假设他的节点为x,在set中左边/右边的节点分别是l,r,那么ans+=path(l,x)+path(x,r)-path(l,r),对于某一点异象石消失,那么操作类似,对于每次询问,我们输出ans即可。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 #include <set>
  7 #include <cmath>
  8 using namespace std;
  9 typedef long long ll;
 10 typedef set<int>::iterator It;
 11 It it;
 12 struct node {
 13     int next,to,dis;
 14 }a[100010<<1];
 15 int head[100010<<1],num,vis[100010],tot,n,m,fvis[100010],d[100010],f[100010][23];
 16 ll ans,dis[100010][23];
 17 queue<int> q;
 18 set<int> s;
 19 char c[2];
 20 inline void add(int from,int to,int dis) {
 21     a[++num].next=head[from]; a[num].to=to; a[num].dis=dis; head[from]=num;
 22 }
 23 void bfs() {
 24     vis[1]=1;
 25     d[1]=1;
 26     q.push(1);
 27     while(q.size()) {
 28         int now=q.front();
 29         q.pop();
 30         for(int i=head[now];i;i=a[i].next) {
 31             int v=a[i].to;
 32             if(vis[v]) continue ;
 33             q.push(v); vis[v]=1; d[v]=d[now]+1;
 34             dis[v][0]=a[i].dis;
 35             f[v][0]=now;
 36             for(int j=1;j<=20;j++) {
 37                 f[v][j]=f[f[v][j-1]][j-1];
 38                 dis[v][j]=dis[v][j-1]+dis[f[v][j-1]][j-1];
 39             }
 40         }
 41     }
 42 }
 43 void dfs(int now) {
 44     vis[now]=++tot;
 45     fvis[tot]=now;
 46     for(int i=head[now];i;i=a[i].next)
 47         if(!vis[a[i].to]) dfs(a[i].to);
 48 }
 49 ll lca(int x,int y) {
 50     ll ret=0;
 51     if(d[x]>d[y]) swap(x,y);
 52     for(int i=20;i>=0;i--)
 53         if(d[f[y][i]]>=d[x]) {
 54             ret+=dis[y][i];
 55             y=f[y][i];
 56         } 
 57     if(x==y) return ret;
 58     for(int i=20;i>=0;i--)
 59         if(f[x][i]!=f[y][i]) {
 60             ret+=dis[x][i]+dis[y][i];
 61             x=f[x][i];
 62             y=f[y][i];
 63         }
 64     return ret+dis[x][0]+dis[y][0];
 65 }
 66 inline It turnl(It it) {
 67     if(it==s.begin()) return --s.end();
 68     return --it;
 69 }
 70 inline It turnr(It it) {
 71     if(it==--s.end()) return s.begin();
 72     return ++it;
 73 }
 74 int main() {
 75     scanf("%d",&n);
 76     for(int i=1,x,y,z;i<n;i++) {
 77         scanf("%d%d%d",&x,&y,&z);
 78         add(x,y,z);
 79         add(y,x,z);
 80     }
 81     bfs();
 82     memset(vis,0,sizeof(vis)); tot=0;
 83     dfs(1);
 84     scanf("%d",&m);
 85     while(m--) {
 86         scanf("%s",c);
 87         if(c[0]=='+') {
 88             int x;
 89             scanf("%d",&x);
 90             if(s.size()) {
 91                 it=s.lower_bound(vis[x]);
 92                 if(it==s.end()) it=s.begin();
 93                 int y=*turnl(it);
 94                 ans+=lca(x,fvis[y])+lca(x,fvis[*it])-lca(fvis[y],fvis[*it]);
 95             }
 96             s.insert(vis[x]);
 97         }
 98         else if(c[0]=='-') {
 99             int x;
100             scanf("%d",&x);
101             it=s.find(vis[x]);
102             int y=*turnl(it);
103             it=turnr(it);
104             ans-=lca(x,fvis[y])+lca(x,fvis[*it])-lca(fvis[y],fvis[*it]);
105             s.erase(vis[x]);
106         }
107         else if(c[0]=='?') printf("%lld\n",ans/2);
108     }
109     return 0;
110 }
AC Code

猜你喜欢

转载自www.cnblogs.com/shl-blog/p/10802161.html