Kattis:Boxes

Kattis:Boxes

题目链接:https://open.kattis.com/problems/boxes

题目大意:给出$N$个盒子,第$i$个盒子在第$a_i$个盒子内.现在有$Q$个询问,每个询问以$M$开始,问$M$个盒子中共有几个不同的盒子(包含自身).

LCA

在线LCA算法:

树上两点$u$,$v$的最近公共祖先$A$的深度一定为$u$与$v$的简单路径中各点深度的最小值.

我们可以用$ver[2 imes N]$数组按顺序记录dfs先后进出的结点编号(因为记录进出的结点,故有$2 imes N - 1$个元素),以将树形结构拆分为线性结构;用$dep[2 imes N]$数组记录对应结点的深度;用$f[i]$记录第一次进入第$i$个结点时在$ver[2 imes N]$中的下标.

例如下图中,$ver[\,]={1,2,4,2,1,3,1}$,$dep[\,]={0,1,2,1,0,1,0}$,$f[\,]={-1,0,1,5,2}$(用$-1$表示结点$0$不存在)

于是,求$u$与$v$的简单路径中各点深度的最小值,即求$ver[\,f[u]\,]$到$ver[\,f[u]\,]$中各结点深度的最小值(这其中可能会包含$u$的子结点,但其深度必然大于$u$的深度).

而维护$ver[\,f[u]\,]$到$ver[\,f[u]\,]$中各结点深度的最小值,即维护一个线性区间的最小值,采用rmq算法,预处理复杂度为$O(nlgn)$,查询复杂度为$O(1)$.


设$A$为$x$与$y$的最近公共祖先,即$A=LCA(x,y)$.

若$A=x$,则$y$在$x$内;

若$A=y$,则$x$在$y$内;

若$A eq x$且$A eq y$,则$x$和$y$互不包含.

两两枚举最近公共祖先,舍去被包含的结点并用set去重,就可以解决这道题了.

//注意:

//可能不止有一个盒子不被其他盒子包含(因为这个问题卡了三天QAQ)

//可以添加一个虚结点下标为$0$,从而构成一颗树.

整道题的时间复杂度为$O(nlgn+q imes m^2)$

代码如下:

 1 #include <iostream>
 2 #include <vector>
 3 #include <cmath>
 4 #include <set>
 5 #define pb(x) push_back(x)
 6 #define N 200005
 7 #define M 25
 8 #define P 20
 9 using namespace std;
10 vector<int>a[N];
11 set<int>s;
12 int n,q,m,tmp,ans,qm[M];
13 int k,ver[2*N],dep[2*N],f[N],num[N],dp[2*N][P];
14 int dfs(int x,int d){
15     num[x]=1;
16     f[x]=k;
17     dep[k]=d;
18     ver[k++]=x;
19     for(int i=0;i<(int)a[x].size();++i){
20         num[x]+=dfs(a[x][i],d+1);
21         dep[k]=d;
22         ver[k++]=x;
23     }
24     return num[x];
25 }
26 void rmq(int k){
27     for(int i=0;i<k;++i)
28         dp[i][0]=i;
29     for(int j=1;(1<<j)<=k;++j)
30     for(int i=0;i+(1<<j)<=k;++i){
31         int x=dp[i][j-1],y=dp[i+(1<<(j-1))][j-1];
32         dp[i][j]=dep[x]<dep[y]?x:y;
33     }
34 }
35 int LCA(int u,int v){
36     if(u>v)swap(u,v);
37     int len=log(v-u+1.0)/log(2.0);
38     int x=dp[u][len],y=dp[v+1-(1<<len)][len];
39     return ver[dep[x]<dep[y]?x:y];
40 }
41 int main(void){
42     std::ios::sync_with_stdio(false);
43     cin>>n;
44     for(int i=1;i<=n;++i){
45         cin>>tmp;
46         a[tmp].pb(i);
47     }
48     dfs(0,0);
49     rmq(k);
50     cin>>q;
51     while(q--){
52         s.clear();
53         cin>>m;
54         for(int i=0;i<m;++i)
55             cin>>qm[i];
56         for(int i=0;i<m;++i){
57             int tot=qm[i];
58             for(int j=0;j<m;++j){
59                 tmp=LCA(f[tot],f[qm[j]]);
60                 if(tmp==qm[j])tot=tmp;
61             }
62             s.insert(tot);
63         }
64         ans=0;
65         for(set<int>::iterator it=s.begin();it!=s.end();++it)
66             ans+=num[*it];
67         cout<<ans<<"
";
68     }
69 }
原文地址:https://www.cnblogs.com/barrier/p/6476275.html