Codeforces 1062E 题解

给出一棵有根树,1为根结点,接下来q次询问,每次给出一个[l,r]区间,现在允许删掉[l,r]区间内任何一个点,使得所有点的最近公共祖先的深度尽可能大,问删掉的点是哪个点,深度最大是多少。

做法:

线段树维护区间dfs序的最大值,最小值。

首先,区间的LCA等价于区间dfs序的最小值和最大值对应的两个点的LCA。

然后,根据dfs序的性质,当删掉的点的dfs序最大或者最小时,对答案贡献最大。

所以接下来只要去查询区间里的LCA(最小值,次大值),以及LCA(次小值,最大值),两个LCA中深度最大的就是答案。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=1e5+5;
  4 #define ll long long
  5 int ccnt=0;
  6 int n,cnt,f[maxn],d[maxn],siz[maxn],son[maxn],rk[maxn],top[maxn],tid[maxn];//tid:dfs rk:anti-dfs
  7 int d_mx;
  8 struct edge
  9 {
 10     int to,next;
 11 }e[maxn];
 12 int head[maxn];
 13 inline void addedge(int u,int v)
 14 {
 15     e[++ccnt].to=v;
 16     e[ccnt].next=head[u];
 17     head[u]=ccnt;
 18 }
 19 void dfs1(int u,int fa,int depth)
 20 {
 21     f[u]=fa;
 22     d[u]=depth;
 23     d_mx=max(d_mx,d[u]);
 24     siz[u]=1;
 25     for(int i=head[u]; i ; i=e[i].next)
 26     {
 27         int v=e[i].to;
 28         if(v==fa)
 29             continue;
 30         dfs1(v,u,depth+1);
 31         siz[u]+=siz[v];
 32         if(siz[v]>siz[son[u]])
 33             son[u]=v;
 34     }
 35 }
 36 void dfs2(int u,int t)
 37 {
 38     top[u]=t;
 39     tid[u]=++cnt;
 40     rk[cnt]=u;
 41     if(!son[u])
 42         return;
 43     dfs2(son[u],t);
 44     for(int i=head[u]; i ; i=e[i].next)
 45     {
 46         int v=e[i].to;
 47         if(v!=son[u]&&v!=f[u])
 48             dfs2(v,v);
 49     }
 50 }
 51 int LCA(int x,int y)
 52 {
 53     if(x==y)
 54         return x;
 55     int fx=top[x],fy=top[y];
 56     while(fx!=fy)
 57     {
 58         if(d[fx]>=d[fy])
 59         {
 60             x=f[fx];
 61         }
 62         else
 63         {
 64             y=f[fy];
 65         }
 66         fx=top[x];
 67         fy=top[y];
 68     }
 69     if(tid[x]<=tid[y]) return x;
 70     else return y;
 71 }
 72 #define lson o*2
 73 #define rson o*2+1
 74 #define m (l+r)/2
 75 struct segment
 76 {
 77     int mx,mn;
 78 }tr[4*maxn];
 79 inline void pushup(int o)
 80 {
 81     tr[o].mx=max(tr[lson].mx,tr[rson].mx);
 82     tr[o].mn=min(tr[lson].mn,tr[rson].mn);
 83 }
 84 inline int ret(int o,int flag)
 85 {
 86     if(flag) return tr[o].mx;
 87     else return tr[o].mn;
 88 }
 89 void build(int o,int l,int r)
 90 {
 91     if(l==r)
 92     {
 93         tr[o].mx=tr[o].mn=tid[l];
 94         return;
 95     }
 96     build(lson,l,m);
 97     build(rson,m+1,r);
 98     pushup(o);
 99 }
100 int query(int o,int l,int r,int ql,int qr,int flag)//1 mx 0 mn
101 {
102     if(ql>qr)
103     {
104         if(flag) return 0;
105         else return maxn;
106     }
107     if(ql<=l&&qr>=r)
108         return ret(o,flag);
109     if(qr<=m)
110         return query(lson,l,m,ql,qr,flag);
111     if(ql>m)
112         return query(rson,m+1,r,ql,qr,flag);
113     if(flag)
114         return max(query(lson,l,m,ql,qr,flag),query(rson,m+1,r,ql,qr,flag));
115     else
116         return min(query(lson,l,m,ql,qr,flag),query(rson,m+1,r,ql,qr,flag));
117 }
118 int main()
119 {
120     int n,q;
121     scanf("%d%d",&n,&q);
122     for(int i=2;i<=n;i++)
123     {
124         int j;
125         scanf("%d",&j);
126         addedge(j,i);
127     }
128     dfs1(1,0,0);
129     dfs2(1,1);
130     build(1,1,n);
131     while(q--)
132     {
133         int l,r;
134         scanf("%d%d",&l,&r);
135         if(l==r) printf("%d %d\n",l,d_mx);
136         int mx=query(1,1,n,l,r,1);
137         int mn=query(1,1,n,l,r,0);
138         mx=rk[mx];
139         mn=rk[mn];
140         int cmx=max(query(1,1,n,l,mx-1,1),query(1,1,n,mx+1,r,1));
141         int cmn=min(query(1,1,n,l,mn-1,0),query(1,1,n,mn+1,r,0));
142         cmx=rk[cmx];
143         cmn=rk[cmn];
144         int lca1=LCA(mx,cmn);
145         int lca2=LCA(mn,cmx);
146         if(d[lca1]<d[lca2])
147             printf("%d %d\n",mx,d[lca2]);
148         else
149             printf("%d %d\n",mn,d[lca1]);
150     }
151 }
View Code

猜你喜欢

转载自www.cnblogs.com/iamamori/p/9965527.html
今日推荐