【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
标签:CH,return,异象石,int,56C,set,path,include,dis 来源: https://www.cnblogs.com/shl-blog/p/10802161.html