题意

题目链接

分析

  • 假设当前的根为 rt ,我们能够在奶牛到达 \(u\) 之时拦住它,当且仅当到叶子节点到 \(u\) 的最短距离 \(mn_u \le dis_u\) 。容易发现,合法的区域是许多棵子树,而我们要求的就是有多少棵子树。
  • 由于除了以 rt 为根的子树都可以用 \(\sum\limits_{x\in subtree} 2-deg(x)\) 的形式表示 (如果 rt 是叶子特判掉即可),于是可以将问题转化成有多少个点满足 \(mn_u\le dis_u​\) 。
  • 考虑点分治,先补集转化这样不用处理负权。每次求对于 \(a\) 有多少 \(b\) 满足 \(dis_a+dis_b<mn_b\) 。把所有路径按照 \(mn_b-dis_b​\) 的大小排序后在序列上二分差后缀和即可。最后要容斥减去子树内的方案数。
  • 时间复杂度 \(O(nlog^2n)​\) 。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
#define re(x) memset(x, 0, sizeof x)
inline int gi() {
int x = 0,f = 1;
char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
return x * f;
}
template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
const int N = 7e4 + 7, inf = 0x3f3f3f3f;
int n, rt, edc, sn;
int mn[N], deg[N], ans[N], mxs[N], head[N], son[N];
bool vis[N];
struct edge {
int lst, to;
edge(){}edge(int lst, int to):lst(lst), to(to){}
}e[N << 1];
void Add(int a, int b){
++deg[a], ++deg[b];
e[++edc] = edge(head[a], b), head[a] = edc;
e[++edc] = edge(head[b], a), head[b] = edc;
}
void bfs() {
queue<int>Q;
memset(mn, 0x3f, sizeof mn);
rep(i, 1, n) if(deg[i] == 1) {
mn[i] = 0, Q.push(i);
}
while(!Q.empty()) {
int u = Q.front();Q.pop();
go(u)if(mn[v] == inf) {
mn[v] = mn[u] + 1;
Q.push(v);
}
}
}
int tp;
typedef pair<int, int> pii;
#define mp make_pair
pii suf[N];
void getrt(int u, int fa) {
mxs[u] = 0;son[u] = 1;
go(u)if(!vis[v] && v ^ fa) {
getrt(v, u);
son[u] += son[v];
Max(mxs[u], son[v]);
}
Max(mxs[u], sn - son[u]);
if(mxs[u] < mxs[rt]) rt = u;
}
void getdep(int u, int fa, int dis) {
if(mn[u] - dis > 0) suf[++tp] = mp(mn[u] - dis, 2 - deg[u]);
go(u)if(!vis[v] && v ^ fa) {
getdep(v, u, dis + 1);
}
}
void getans(int u, int fa, int dis, int f) {
int gg = upper_bound(suf + 1, suf + 1 + tp, mp(dis, inf)) - suf;
if(gg != tp + 1)
ans[u] += f * suf[gg].second;
go(u)if(!vis[v] && v ^ fa) {
getans(v, u, dis + 1, f);
}
}
void solve(int u) {
vis[u] = 1;
tp = 0;
getdep(u, 0, 0);
sort(suf + 1, suf + 1 + tp);
for(int j = tp - 1; j >= 1; --j) suf[j].second += suf[j + 1].second;
getans(u, 0, 0, 1); go(u)if(!vis[v]) {
tp = 0;
getdep(v, u, 1);
sort(suf + 1, suf + 1 + tp);
for(int j = tp - 1; j >= 1; --j) suf[j].second += suf[j + 1].second;
getans(v, u, 1, -1);
} int old = sn;
go(u)if(!vis[v]) {
if(son[v] > son[u])
sn = old - son[u];
else
sn = son[v];
rt = 0, getrt(v, u), solve(rt);
}
}
int main() {
n = gi();
rep(i, 1, n - 1) Add(gi(), gi());
bfs();
sn = n, mxs[rt = 0] = n + 1, getrt(1, 0), solve(rt);
rep(i, 1, n) printf("%d\n", deg[i] == 1 ? 1 : 2 - ans[i]);
return 0;
}

[LOJ#2386]. 「USACO 2018.01 Platinum」Cow at Large[点分治]的更多相关文章

  1. @loj - 6353@「CodePlus 2018 4 月赛」组合数问题 2

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 请你找到 k 个不同的组合数,使得对于其中任何一个组合数 \(C ...

  2. LOJ#6354. 「CodePlus 2018 4 月赛」最短路[最短路优化建图]

    题意 一个 \(n\) 个点的完全图,两点之间的边权为 \((i\ xor\ j)*C\) ,同时有 \(m\) 条额外单向路径,问从 \(S\) 到 \(T\) 的最短路. \(n\leq 10^5 ...

  3. loj #6302. 「CodePlus 2018 3 月赛」寻找车位【线段树+单调队列】

    考虑静态怎么做:枚举右边界,然后枚举上边界,对应的下边界一定单调不降,单调栈维护每一列从当前枚举的右边界向左最长空位的长度,这样是O(nm)的 注意到n>=m,所以m<=2000,可以枚举 ...

  4. [LOJ #2833]「JOISC 2018 Day 1」帐篷

    题目大意:有一个$n\times m$的网格图,若一个人的同一行或同一列有人,他就必须面向那个人,若都无人,就可以任意一个方向.若一个人无法确定方向,则方案不合法,问不同的方案数.$n,m\leqsl ...

  5. LOJ 2840「JOISC 2018 Day 4」糖

    有趣的脑子题(可惜我没有脑子 好像也可以称为模拟费用流(? 我们考虑用链表维护这个东西 再把贡献扔到堆里贪心就好了 大概就是类似于有反悔机制的贪心?我们相当于把选中的一个打上一个-v的tag然后如果选 ...

  6. loj#2838 「JOISC 2018 Day 3」比太郎的聚会

    分析 预处理每个点的前根号小的距离 对于每次询问删除点小于根号则已经处理好 否则直接暴力dp即可 代码 #include<bits/stdc++.h> using namespace st ...

  7. @loj - 6354@「CodePlus 2018 4 月赛」最短路

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 企鹅国中有 N 座城市,编号从 1 到 N . 对于任意的两座城 ...

  8. LOJ #2831. 「JOISC 2018 Day 1」道路建设 线段树+Link-cut-tree

    用 LCT 维护颜色相同连通块,然后在线段树上查一下逆序对个数就可以了. code: #include <cstdio> #include <algorithm> #inclu ...

  9. LOJ #2802. 「CCC 2018」平衡树(整除分块 + dp)

    题面 LOJ #2802. 「CCC 2018」平衡树 题面有点难看...请认真阅读理解题意. 转化后就是,给你一个数 \(N\) ,每次选择一个 \(k \in [2, N]\) 将 \(N\) 变 ...

随机推荐

  1. Android为TV端助力 handler ,message消息发送方式

    1.Message msg =  Message.obtain(mainHandler) msg.obj=obj;//添加你需要附加上去的内容 msg.what = what;//what消息处理的类 ...

  2. Ubuntu添加新分区

    1.查看分区 ~$ sudo fdisk -l 2.添加分区 ~$ fdisk /dev/sda 3.输入m查看帮助 ~$ m 4.输入n新建分区,即添加分区 ~$ n 这里会出现设置分区大小 5.输 ...

  3. 使用VSTS的Git进行版本控制(四)——在Visual Studio中管理分支

    使用VSTS的Git进行版本控制(四)--在Visual Studio中管理分支 可以从web版Team Services Git repo 的Branches视图中管理工作.定制视图来跟踪最关注的分 ...

  4. Windows服务器防火墙配置规范

    本文属于一篇内部规范文档,整理的初衷是为了规范.统一集团的Windows服务器(仅仅SQL Server数据库服务器)防火墙设置,仅仅供内部其它同事设置Windows防火墙时作为参考的文档资料.如有不 ...

  5. mssql sqlserver两条求和sql脚本相加的方法分享

    转自:http://www.maomao365.com/?p=7205 摘要: 下文分享两条sql求和脚本,再次求和的方法分享 /* 例: 下文已知两条sql求和脚本,现需对两张不同表的求和记录再次求 ...

  6. MSSQL 如何采用sql语句 获取建表字段说明、字段备注、字段类型、字段长度

    转自: http://www.maomao365.com/?p=4983 <span style="color:red;font-weight:bold;">下文讲述- ...

  7. c/c++ lambda 表达式 剖析

    lambda 表达式 剖析 大前提:捕获列表里变量的确定时机. 捕获列表和参数列表有区别,捕获列表里的变量,是在捕获的时间点就确定了,而不是在lambda调用时确定,参数列表是在调用时才确定.所以当捕 ...

  8. iOS图片存在本地、再从本地获取图片

    图片存在本地.再从本地获取图片 //将图片保存到本地 + (void)SaveImageToLocal:(UIImage*)image Keys:(NSString*)key {     NSUser ...

  9. 使用Navicat for Mysql连接mysql服务器

    使用Navicat for Mysql连接mysql服务器 在windows上用Navicat for Mysql 连接装在虚拟机Ubuntu上的mysql服务器时出现的问题的解决方案. Navica ...

  10. 如何用Jupyter notebook打开本地数据集

    首先打开本地Jupyter notebook,出现类似页面并进入网页端Home. 网页端界面类似如下: 需要注意的是,Jupyter notebook只能打开当前目录下的数据集,如csv,所以需要使用 ...