[nowcoder]contest/172/C保护

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 }
原文地址:https://www.cnblogs.com/Slrslr/p/10060247.html