C国有n个城市,城市间通过一个树形结构形成一个连通图。城市编号为1到n,其中1号城市为首都。国家有m支军队,分别守卫一条路径的城市。具体来说,对于军队i,他守卫的城市区域可以由一对二元组(xi,yi)代表。表示对于所有在xi到yi的最短路径上的城市,军队i都会守卫他们。
现在有q个重要人物。对于一个重要人物j,他要从他的辖区vj出发,去到首都。出于某些原因,他希望找到一个离首都最近的,且在vj到首都路径上的城市uj,使得至少有kj支军队,能够全程保护他从vj到uj上所经过的所有城市。换句话说,至少有ki支军队,满足在树上,xi到yi的路径能完全覆盖掉vj到uj的路径。
貌似主席树维护$DFS$序这种题目用线段树合并都可以搞,好像本质上都是按照$DFS$序建树
首先把一条覆盖路径拆成两点到$LCA$的两条路径(套路)
然后我们二分这个最小深度,可以发现,如果子树内的路径端点大于二分深度的个数大于等于$k$,那么该深度就合法
然后子树的的信息显然可以用线段树合并维护,二分过程也可以用线段树二分实现
总复杂度$(nlogn)$
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<vector> 5 #define M 200010 6 #define ls ch[node][0] 7 #define rs ch[node][1] 8 using namespace std; 9 vector<int>S[M],Q[M]; 10 int n,m,num,cnt,q; 11 int head[M],deep[M],ans[M],a[M],f[M],sz[M],son[M],top[M],rt[M]; 12 int val[M<<8],ch[M<<8][2]; 13 struct point{int to,next;}e[M<<1]; 14 void add(int from,int to) { 15 e[++num].next=head[from]; 16 e[num].to=to; 17 head[from]=num; 18 } 19 void dfs1(int x) { 20 deep[x]=deep[f[x]]+1,sz[x]=1; 21 for(int i=head[x];i;i=e[i].next) { 22 int to=e[i].to; 23 if(to==f[x]) continue; 24 f[to]=x;dfs1(to),sz[x]+=sz[to]; 25 if(sz[son[x]]<sz[to]) son[x]=to; 26 } 27 } 28 void dfs2(int x,int tp) { 29 top[x]=tp; 30 if(son[x]) dfs2(son[x],tp); 31 for(int i=head[x];i;i=e[i].next) 32 if(e[i].to!=f[x]&&e[i].to!=son[x]) 33 dfs2(e[i].to,e[i].to); 34 } 35 int lca(int x,int y) { 36 while(top[x]!=top[y]) { 37 if(deep[top[x]]<deep[top[y]]) swap(x,y); 38 x=f[top[x]]; 39 } 40 return deep[x]<deep[y]?x:y; 41 } 42 void insert(int &node,int l,int r,int x,int v) { 43 if(!node) node=++cnt;val[node]+=v; 44 if(l==r) return; 45 int mid=(l+r)/2; 46 if(x<=mid) insert(ls,l,mid,x,v); 47 else insert(rs,mid+1,r,x,v); 48 } 49 int query(int node,int l,int r,int d) { 50 if(val[node]<d) return -1; 51 if(l==r) return l; 52 int mid=(l+r)/2; 53 if(d<=val[ls]) return query(ls,l,mid,d); 54 else return query(rs,mid+1,r,d-val[ls]); 55 } 56 int merge(int x,int y,int l,int r) { 57 if(!x||!y) return x+y; 58 int node=++cnt; 59 if(l==r) { 60 val[node]=val[x]+val[y]; 61 return node; 62 } 63 int mid=(l+r)/2; 64 ls=merge(ch[x][0],ch[y][0],l,mid); 65 rs=merge(ch[x][1],ch[y][1],mid+1,r); 66 val[node]=val[ls]+val[rs]; 67 return node; 68 } 69 void dfs(int x,int fa) { 70 for(int i=0;i<S[x].size();i++) 71 insert(rt[x],1,n,S[x][i],1); 72 for(int i=head[x];i;i=e[i].next) 73 if(e[i].to!=fa) 74 dfs(e[i].to,x); 75 for(int i=head[x];i;i=e[i].next) 76 if(e[i].to!=fa) 77 rt[x]=merge(rt[x],rt[e[i].to],1,n); 78 for(int i=0;i<Q[x].size();i++) { 79 int id=Q[x][i],u=a[id]; 80 int res=query(rt[x],1,n,u); 81 if(res==-1||res>deep[x]) ans[id]=0; 82 else ans[id]=deep[x]-res; 83 } 84 } 85 int main() { 86 scanf("%d%d",&n,&m); 87 for(int i=1;i<n;i++) { 88 int x,y;scanf("%d%d",&x,&y); 89 add(x,y),add(y,x); 90 } 91 dfs1(1),dfs2(1,1); 92 for(int i=1;i<=m;i++) { 93 int x,y;scanf("%d%d",&x,&y); 94 int LCA=lca(x,y); 95 if(x!=LCA) S[x].push_back(deep[LCA]); 96 if(y!=LCA) S[y].push_back(deep[LCA]); 97 } 98 scanf("%d",&q); 99 for(int i=1;i<=q;i++) { 100 int x,y;scanf("%d%d",&x,&y); 101 a[i]=y;Q[x].push_back(i); 102 } 103 dfs(1,0); 104 for(int i=1;i<=q;i++) printf("%d ",ans[i]); 105 return 0; 106 }