题目大意

一棵 \(n(1\leq n\leq 2\times 10^5)\) 个节点以 \(1\) 为根的树,分别求以 \(1\sim n\) 为根的子树中有多少个节点编号连续的段。 \(T(1\leq T\leq 10)\) 组数据, \(\sum_{i=1}^{T}n\leq 10^6\) 。

思路

将子树按 \(dfs\) 序转化为区间,之后求区间内有多少个数字连续的段。我们可以使用树状数组,用一个 \(vis[\space]\) 来记录每个数字是否出现过,我们对区间从前往后遍历,对于每一个数字 \(i\) ,如果 \(i-1,i+1\) 都没有出现过,说明是新的一段,于是在这个位置 \(+1\) ;如果二者仅有一个出现过,说明段数没有变化;如果都出现过,说明有两个段被合并为了一个段,于是需要在这个位置 \(-1\)。这样查询区间 \([1,x]\) 的时候就是对前 \(x\) 个位置上的数求和即可。如果查询的左端点不是 \(1\) 那么我们要考虑去掉左侧不属于查询区间部分的影响,对于其中的每一个数字 \(i\) ,其会影响到 \(i-1,i+1\) 对应位置上的值,因为 \(i\) 是更早出现的,所以此时我们把那两个值 \(+1\) , 将 \(i\) 对应位置上的值置为 \(0\) ,然后对于查询区间 \([l,r]\) ,答案依然是前 \(r\) 个值的和。我们对所有询问按查询的左端点排序,依次查询即可,复杂度 \(O(nlogn)\) 。

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
#define all(x) x.begin(),x.end()
//#define int LL
//#define lc p*2+1
//#define rc p*2+2
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#pragma warning(disable :4996)
const long double eps = 1e-15;
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 200010; int T, N, cnt = 0;
vector<int>G[maxn];
int dfn[maxn], in[maxn], out[maxn], rnk = 0, A[maxn];
bool vis[maxn];
int dat[maxn], n, ans[maxn], val[maxn];
struct Query{
int l, r, id;
}Q[maxn]; bool cmp(const Query& a, const Query& b)
{
return a.l < b.l;
} void add(int i, int x)
{
while (i <= n)
{
dat[i] += x;
i += i & (-i);
}
} int sum(int i)
{
int ans = 0;
while (i)
{
ans += dat[i];
i -= i & (-i);
} return ans;
} void add_edge(int from, int to)
{
G[from].push_back(to);
G[to].push_back(from);
} void dfs(int v, int p)
{
in[v] = dfn[v] = ++rnk;
A[dfn[v]] = v;
val[dfn[v]] = 0;
for (int i = 0; i < G[v].size(); i++)
{
int to = G[v][i];
if (to == p)
continue;
dfs(to, v);
}
out[v] = rnk;
} void solve()
{
rnk = 0;
dfs(1, 0);
n = N;
for (int i = 1; i <= N; i++)
{
if (!vis[A[i] + 1] && !vis[A[i] - 1])
{
add(i, 1);
val[i]++;
}
else if (vis[A[i] + 1] && vis[A[i] - 1])
{
add(i, -1);
val[i]--;
}
vis[A[i]] = true;
} for (int i = 1; i <= N; i++)
Q[i] = Query({ in[i], out[i], i });
sort(Q + 1, Q + N + 1, cmp);
int nl = 1;
for (int i = 1; i <= N; i++)
{
int l = Q[i].l, r = Q[i].r;
while (nl < l)
{
if (A[nl] != N && dfn[A[nl] + 1] > nl)
{
add(dfn[A[nl] + 1], 1);
val[dfn[A[nl] + 1]]++;
}
if (A[nl] != 1 && dfn[A[nl] - 1] > nl)
{
add(dfn[A[nl] - 1], 1);
val[dfn[A[nl] - 1]]++;
}
add(nl, -val[nl]);
val[nl] = 0;
nl++;
}
ans[Q[i].id] = sum(r);
}
cout << "Case #" << cnt << ": ";
for (int i = 1; i <= N; i++)
cout << ans[i] << (i == N ? endl : ' ');
} int main()
{
IOS;
cin >> T;
while (T--)
{
memset(vis, false, sizeof(vis));
memset(dat, 0, sizeof(dat));
cnt++;
cin >> N;
int u, v;
for (int i = 1; i <= N; i++)
G[i].clear();
for (int i = 1; i < N; i++)
{
cin >> u >> v;
add_edge(u, v);
}
solve();
} return 0;
}

2019CCPC Final K. Russian Dolls on the Christmas Tree的更多相关文章

  1. POJ Big Christmas Tree(最短的基础)

    Big Christmas Tree 题目分析: 叫你构造一颗圣诞树,使得 (sum of weights of all descendant nodes) × (unit price of the ...

  2. POJ3013 Big Christmas Tree[转换 最短路]

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 23387   Accepted: 5 ...

  3. poj 3013 Big Christmas Tree (最短路径Dijsktra) -- 第一次用优先队列写Dijsktra

    http://poj.org/problem?id=3013 Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total S ...

  4. poj 3013 Big Christmas Tree Djistra

    Big Christmas Tree 题意:图中每个节点和边都有权值,图中找出一颗树,树根为1使得 Σ(树中的节点到树根的距离)*(以该节点为子树的所有节点的权值之和) 结果最小: 分析:直接求出每个 ...

  5. POJ 3013 Big Christmas Tree(最短Dijkstra+优先级队列优化,SPFA)

    POJ 3013 Big Christmas Tree(最短路Dijkstra+优先队列优化,SPFA) ACM 题目地址:POJ 3013 题意:  圣诞树是由n个节点和e个边构成的,点编号1-n. ...

  6. poj 3013 Big Christmas Tree

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 20974   Accepted: 4 ...

  7. Big Christmas Tree(poj-3013)最短路

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 25823   Accepted: 5 ...

  8. 2019CCPC秦皇岛 K MUV LUV UNLIMITED(博弈)

    MUV LUV UNLIMITED Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  9. HDU - 5156 Harry and Christmas tree

    题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=5156 题意 : 给一颗编号为1-n的以1为根的树, 已知有m个颜色的礼物分布在某些节点上(同一节点 ...

随机推荐

  1. 集合框架-HashSet集合(无序唯一)

    1 package cn.itcast.p4.hashset.demo; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 /* ...

  2. makefile 编译多个目标

    1.静态库libtools.a源码 libtools.h #ifndef tools_h_ #define tools_h_ int sub(int x,int y); int mul(int x,i ...

  3. ApacheCN PythonWeb 译文集 20211028 更新

    Django By Example 中文版 1 创建一个博客应用 2 为博客添加高级功能 3 扩展你的博客应用 4 创建一个社交网站 5 分享内容到你的网站 6 跟踪用户动作 7 构建在线商店 8 管 ...

  4. Swift数组

    数组的介绍 数组(Array)是一串有序的由相同类型元素构成的集合 数组中的集合元素是有序的,可以重复出现 Swift中的数组 swift数组类型是Array,是一个泛型集合 数组的初始化 数组分成: ...

  5. Docker入门 安装 基础操作命令

    Docker 学习来源 https://www.bilibili.com/video/av26993050/?spm_id_from=333.788.b_636f6d6d656e74.20 https ...

  6. linux上printf出带颜色字体

    转载请注明来源:https://www.cnblogs.com/hookjc/ 统一定义: #define NONE         "\033[m"  #define RED   ...

  7. java创建一个子类对象是会调用父类的构造方法会不会创建父类

    1.子类在创建实例后,类初始化方法会调用父类的初始化方法(除了Java.lang.Object类,因为java.lang.Object类没有父类),而这种调用会逐级追述,直到java.lang.Obj ...

  8. HDOJ 1249 三角形『平面分隔』

    很水拉   为了记规律- - 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1249 分隔平面公式 下面是我自己查找的公式,没有推到过程,但可以给一些链 ...

  9. P2678 [NOIP2015 提高组] 跳石头

    #include<bits/stdc++.h> using namespace std; int l,n,m,a[100010];//与起点的距离 bool check(int d) { ...

  10. 如何从0到1设计一个类Dubbo的RPC框架

    之前分享了如何从0到1设计一个MQ消息队列,今天谈谈"如何从0到1设计一个Dubbo的RPC框架",重点考验: 你对RPC框架的底层原理掌握程度. 以及考验你的整体RPC框架系统设 ...