watch

打印 上一主题 下一主题

主题 545|帖子 545|积分 1635

平常很少做dfs序相干的题,算是复习一下吧。
题目大意

给你一棵树,每个节点有好坏两种颜色,初始都是白色,现在支持以下两种操作:


  • 将一个节点的颜色翻转
  • 询问某个节点与所有黑色节点分别求lca后得到的深度最大的结果
                                    n                         ,                         q                         ≤                         8                         ×                         1                                   0                            5                                       n,q≤8 \times 10^5                  n,q≤8×105。
题解

有一个著名但是赛时被我忘了的结论,某个点与一个特定点集合的lca中深度最大的必定是跟这个点dfs序最接近的两个点(前驱和后继)中的一个。
那么就变成蠢题了,对于翻转操作维护一下点集合,询问操作每次只需要找到dfs序的前驱后继并求lca再比力即可。对于维护和查找官方题解用的是线段树,而我选择set。
Code

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=8e5+5;
  4. int n,m,cnt,num,a[N],fa[N],dep[N],siz[N],dfn[N],tid[N],top[N],son[N],head[N];
  5. bool b[N];
  6. set<int> s;
  7. struct edge{
  8.         int to,nxt;
  9. }e[N];
  10. void add(int u,int v){
  11.         e[++cnt]=(edge){v,head[u]};
  12.         head[u]=cnt;
  13. }
  14. void dfs1(int u,int f,int d){
  15.         siz[u]=1,fa[u]=f,dep[u]=d;
  16.         for(int i=head[u];i;i=e[i].nxt){
  17.                 int v=e[i].to;
  18.                 dfs1(v,u,d+1);
  19.                 siz[u]+=siz[v];
  20.                 if(siz[v]>siz[son[u]]) son[u]=v;
  21.         }
  22. }
  23. void dfs2(int u,int tp){
  24.         dfn[u]=++num,tid[num]=u,top[u]=tp;
  25.         if(!son[u]) return;
  26.         dfs2(son[u],tp);
  27.         for(int i=head[u];i;i=e[i].nxt){
  28.                 int v=e[i].to;
  29.                 if(v==son[u]) continue;
  30.                 dfs2(v,v);
  31.         }
  32. }
  33. int lca(int x,int y){
  34.         while(top[x]!=top[y]){
  35.                 if(dep[top[x]]<dep[top[y]]) swap(x,y);
  36.                 x=fa[top[x]];
  37.         }
  38.         return dep[x]<dep[y]?x:y;
  39. }
  40. int main(){
  41.         freopen("watch.in","r",stdin);
  42.         freopen("watch.out","w",stdout);
  43.         scanf("%d%d",&n,&m);
  44.         for(int i=2,x;i<=n;i++){
  45.                 scanf("%d",&x);
  46.                 add(x,i);
  47.         }
  48.         dfs1(1,0,0);
  49.         dfs2(1,1);
  50.         for(int i=1,x;i<=m;i++){
  51.                 scanf("%d",&x);
  52.                 if(x>0){
  53.                         b[x]=!b[x];
  54.                         if(b[x]) s.insert(dfn[x]);
  55.                         else s.erase(dfn[x]);
  56.                 }
  57.                 else{
  58.                         x=-x;
  59.                         if(s.size()==0){
  60.                                 printf("0\n");
  61.                                 continue;
  62.                         }
  63.                         set<int>::iterator it=s.lower_bound(dfn[x]);
  64.                         int ans1=0,ans2=0;
  65.                         if(it!=s.end()) ans1=lca(tid[*it],x);
  66.                         if(it!=s.begin()){
  67.                                 it--;
  68.                                 ans2=lca(tid[*it],x);
  69.                         }
  70.                         if(!ans1&&!ans2) printf("0\n");
  71.                         else if(!ans1||!ans2) printf("%d\n",ans1+ans2);
  72.                         else printf("%d\n",dep[ans1]>dep[ans2]?ans1:ans2);
  73.                 }
  74.         }
  75.         return 0;
  76. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

欢乐狗

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表