保护

题目描述

\(C\)国有\(n\)个城市,城市间通过一个树形结构形成一个连通图。城市编号为\(1\)到\(n\),其中\(1\)号城市为首都。国家有\(m\)支军队,分别守卫一条路径的城市。具体来说,对于军队\(i\),他守卫的城市区域可以由一对二元组\((x_i,y_i)\)代表。表示对于所有在\(x_i\)到\(y_i\)的最短路径上的城市,军队\(i\)都会守卫他们。

现在有\(q\)个重要人物。对于一个重要人物\(j\),他要从他的辖区\(v_j\)出发,去到首都。出于某些原因,他希望找到一个离首都最近的,且在\(v_j\)到首都路径上的城市\(u_j\),使得至少有\(k_j\)支军队,能够全程保护他从\(v_j\)到\(u_j\)上所经过的所有城市。换句话说,至少有\(k_i\)支军队,满足在树上,\(x_i\)到\(y_i\)的路径能完全覆盖掉\(v_j\)到\(u_j\)的路径。

输入描述:

第一行输入两个数\(n\),\(m\)。

接下来\(n-1\)行,每行两个整数\(u\),\(v\),表示存在一条从城市\(u\)到城市\(v\)的道路。

接下来\(m\)行,每行两个整数\(x\),\(y\)。描述一个军队的守卫区域。

接下来一行一个整数\(q\)。

接下来\(q\)行,每行两个整数\(v_j,k_j\)。

输出描述:

对于每次询问,输出从\(v_j\)到\(u_j\)最少需要经过多少条边。假如不存在这样的\(u_j\),则输出\(0\)。

备注:

20%: n,m,q <= 300

40%: n,m,q <= 2000

60%: n,m,q <= 50000

100%: n,m,q <= 200000

覆盖必须是完全覆盖,不可以每个军队保护不同的段


设军队有为三元组\((x,y,z)\)

其中,\(x,y\)为军队的链端点,\(z\)为它们的\(LCA\)的深度

可以知道,每次询问\((v,k)\)都是查询满足\(dfn_v \le x \le low_v\)或\(dfn_v \le y \le low_v\)的第\(k\)小\(z\)值

\(dfn_v\)~\(low_v\)是整棵子树的dfs序

可以直接CDQ套主席树求解

upd:不需要套CDQ,借助差分的思想,主席树就可以解决 有一道基本一样的题可以看看[CQOI2015]任务查询系统

然而也可以用神奇的启发式合并

对每个节点建一颗权值线段树,代表这个节点的子树所包含的\(x\)或\(y\)的\(z\)值集合

注意这里并不需要容斥,因为如果\(x,y\)在同一颗子树那它们一定无法对这个子树根做出贡献

具体的,我们可以建出每个节点自己的\(z\)值集合,然后dfs合并上去

我这里直接用了子树的节点,所以会破坏子树的结构,于是先读进来然后离线做了

在线也可以,不过要多开一些节点


Code:

#include <cstdio>
#include <vector>
using namespace std;
const int N=2e5+10;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int f[N][19],dep[N],n,m,q;
void dfs_(int now)
{
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
if(v!=f[now][0])
{
f[v][0]=now;
dep[v]=dep[now]+1;
for(int j=1;j<=18;j++)
f[v][j]=f[f[v][j-1]][j-1];
dfs_(v);
}
}
}
vector <int > d[N];
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=18;~i;i--)
if(dep[f[x][i]]>=dep[y])
x=f[x][i];
if(x==y) return x;
for(int i=18;~i;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int sum[N*30],ch[N*30][2],tot,root[N];
#define ls ch[now][0]
#define rs ch[now][1]
void change(int &now,int l,int r,int pos)
{
if(!now) now=++tot;
if(l==r) {++sum[now];return;}
int mid=l+r>>1;
if(pos<=mid) change(ls,l,mid,pos);
else change(rs,mid+1,r,pos);
sum[now]=sum[ls]+sum[rs];
}
#define ols ch[las][0]
#define ors ch[las][1]
void Merge(int &now,int las,int l,int r)
{
if(!now||!las) {now=las+now;return;}
if(l==r) {sum[now]+=sum[las];return;}
int mid=l+r>>1;
Merge(ls,ols,l,mid);
Merge(rs,ors,mid+1,r);
sum[now]=sum[ls]+sum[rs];
}
struct node
{
int i,k;
node(){}
node(int i,int k){this->i=i,this->k=k;}
}tt;
vector <node > ask[N];int ans[N];
int query(int now,int l,int r,int k)
{
if(l==r) return l;
int mid=l+r>>1;
if(sum[ls]>=k) return query(ls,l,mid,k);
else return query(rs,mid+1,r,k-sum[ls]);
}
void dfs(int now)
{
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
if(f[now][0]!=v)
{
dfs(v);
Merge(root[now],root[v],1,n);
}
}
for(int k,i=0;i<ask[now].size();i++)
{
k=ask[now][i].k;
ans[ask[now][i].i]=max(0,dep[now]-query(root[now],1,n,k));
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int u,v,i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dep[1]=1;
dfs_(1);
for(int u,v,i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
int lca=LCA(u,v);
change(root[u],1,n,dep[lca]);
change(root[v],1,n,dep[lca]);
}
scanf("%d",&q);
for(int v,k,i=1;i<=q;i++)
{
scanf("%d%d",&v,&k);
tt=node(i,k);
ask[v].push_back(tt);
}
dfs(1);
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
return 0;
}

2018.9.9

牛客 NOIp模拟1 T3 保护 解题报告的更多相关文章

  1. 牛客 NOIp模拟1 T1 中位数 解题报告

    中位数 题目描述 小\(N\)得到了一个非常神奇的序列\(A\).这个序列长度为\(N\),下标从\(1\)开始.\(A\)的一个子区间对应一个序列,可以由数对\([l,r]\)表示,代表\(A[l] ...

  2. 牛客练习赛 小A与任务 解题报告

    小A与任务 链接: https://ac.nowcoder.com/acm/contest/369/B 来源:牛客网 题目描述 小A手头有 \(n\) 份任务,他可以以任意顺序完成这些任务,只有完成当 ...

  3. 牛客OI周赛7-普及组 解题报告

    出题人好评. 评测机差评. A 救救喵咪 二位偏序.如果数据范围大的话直接树状数组,不过才1000就\(O(n^2)\)暴力就ok了. #include <bits/stdc++.h> s ...

  4. nowcoder(牛客网)OI测试赛2 解题报告

    qwq听说是一场普及组难度的比赛,所以我就兴高采烈地过来了qwq 然后发现题目确实不难qwq.....但是因为蒟蒻我太蒻了,考的还是很差啦qwq orz那些AK的dalao们qwq 赛后闲来无事,弄一 ...

  5. Solution -「牛客 NOIP 模拟赛」打拳

    \(\mathcal{Description}\)   现 \(2^n\) 个人进行淘汰赛,他们的战力为 \(1\sim 2^n\),战力强者能战胜战力弱者,但是战力在集合 \(\{a_m\}\) 里 ...

  6. 牛客OI赛制测试赛3 解题报告

    前话: 话说考试描述:普及难度. 于是想在这场比赛上涨点信心. 考出来的结果:Point:480     Rank:40 然而同机房的最好成绩是 510. 没考好啊!有点炸心态,D题一些细节没有注意, ...

  7. nowcoder(牛客网)OI测试赛3 解题报告

    昨天因为胡搞了一会儿社团的事情,所以错过(逃过)了nowcoder的测试赛..... 以上,听说还是普及组难度qwq,而且还有很多大佬AK(然而我这么蒻肯定还是觉得有点难度的吧qwq) 不过我还是日常 ...

  8. NOIP模拟2017.6.11解题报告

    T1: 水题: 代码: #include <cstdio> #include <iostream> #include <algorithm> using names ...

  9. NOIP模拟赛-旅行者问题 解题报告

    旅行者问题 [问题描述] lahub是一个旅行者的粉丝,他想成为一个真正的旅行者,所以他计划开始一段旅行.lahub想去参观n个目的地(都在一条直道上).lahub在起点开始他的旅行.第i个目的地和起 ...

随机推荐

  1. 读取hdfs目录,并在web页面上展示文件里的内容

    最终效果图 目录树实体类: /** * @Author: DaleyZou * @Description: hdfs 目录结构的实体类,用于展示目录树的支撑操作 * @Date: Created in ...

  2. JS - 给String.prototype添加replaceAll方法

    String.prototype.replaceAll = function (targetStr, newStr) {  var sourceStr = this.valueOf();  while ...

  3. django+xadmin在线教育平台(十)

    剩余app model注册 courses注册 新建courses/adminx.py: # encoding: utf-8 __author__ = 'mtianyan' __date__ = '2 ...

  4. centos 7 编译安装mysql 详细过程

    一.配置防火墙,开启80端口.3306端口 CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙. 1.关闭firewall: systemctl stop fi ...

  5. AWS CentOS7 实例修改主机名

    问题描述: AWS EC2 实例在升级到CentOS7以后,我们发现主机名的修改不再像之前的版本(CentOS 5/6)一样简单. 每次新建实例之后,修改好主机名,重启或者克隆之后的机器,主机名还是会 ...

  6. 【转载】C++中的static关键字的总结

    本文前半部分转自:博主chao_yu 本文后半部分转自:博主VincentCZW 静态变量作用范围在一个文件内,程序开始时分配空间,结束时释放空间,默认初始化为0,使用时可以改变其值. 静态变量或静态 ...

  7. Laravel系列之CMS系统学习 — 角色、权限配置【1】

    一.后台Admin模块 后台管理是有管理员的,甚至超级管理员,所以在设计数据表的时候,就会有2个方案,一个方案是共用users数据表,添加is_admin,is_superAdmin字段来进行验证,或 ...

  8. python_字符串_常用处理

    1. 输出原序列的反向互补序列 in1 = open("brca1.fasta", "r") out1 = open("re_brca1.fasta& ...

  9. LeetCode summary

    https://www.programcreek.com/2013/08/leetcode-problem-classification/ https://medium.com/algorithms- ...

  10. QToolBox学习笔记

    抽屉控件效果类似于QQ界面 最外面一层叫工具盒QToolBox QToolBox中装的是QGroupBox,分组的盒子 在分组的盒子QGroupBox中装的是QToolButton.