热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CodeChef2014AprilChallenge-Chef的最终对决:数据结构与整体二分的应用

本题探讨了在大数据结构背景下,如何通过整体二分和CDQ分治等高级算法优化处理复杂的时间序列问题。题目设定包括节点数量、查询次数和权重限制,并详细分析了解决方案中的关键步骤。

问题描述

给定一棵树,包含n个节点(编号为1到n),每个节点有一个初始值wi (1 ≤ wi ≤ 10^9),以及q次操作。每次操作可能是更新某个节点的值或询问某个子树内非正数节点的数量。要求支持高效的数据结构来处理这些操作。

具体参数范围:
n, q, V ≤ 100,000
wi ≤ 10^9

解决方案

本题的核心难点在于处理带有下取整运算的时间相关修改。这类问题通常需要考虑不同时间点的影响累积方式,而不是简单地将所有变化叠加在一起。

我们观察到,一次更新操作的影响范围有限,仅限于距离不超过log(n)的节点。基于此特性,我们可以设计一个复杂度为O(q log n log² V)的初步算法:

  • 对于子树内的节点,根据BFS序维护受影响区间的减法操作。
  • 对于被修改节点的祖先节点,同样按照其对应深度进行相应调整,注意去除重复影响。

为了进一步优化,我们引入了一种更高效的策略:首先不直接处理子树,而是每次只修改当前节点及其祖先节点。通过记录tag[i,j]表示节点i对其第j级子孙的影响,可以将每次修改的复杂度降低至O(log²)。

针对查询子树内非正数节点的问题,可以采用整体二分或CDQ分治的方法。具体来说,我们将所有操作按时间分治,在每个分治区间[l,r]中,标记出哪些节点在此期间变为非正数。通过递归处理左右两个子区间,确保每个节点最多只会被检查O(log n)次。

此外,为了避免频繁插入和撤销操作带来的额外开销,我们使用持久化tag数组存储每次改变的时间戳。这样不仅减少了不必要的计算量,还将总的时间复杂度降至O(Q log² n)。

代码实现

#include 
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 100005
#define LL long long
using namespace std;

int fs[N], nt[2*N], dt[2*N], pr[N], n, m, w[N], dfw[N], sz[N], dfn[N], ans[N], m1, ask[N][3], f[N], dep[N];
LL sm[N];
//tree_array
int c[N];

int lowbit(int k) {
return k & -k;
}

int get(int k) {
int s = 0;
while (k) s += c[k], k -= lowbit(k);
return s;
}

void put(int k) {
while (k <= n) c[k]++, k += lowbit(k);
}

void link(int x, int y) {
nt[++m1] = fs[x];
dt[fs[x] = m1] = y;
}

void dfs(int k, int fa) {
f[k] = fa;
dfw[dfn[k] = ++dfn[0]] = k;
dep[k] = dep[fa] + 1;
sz[k] = 1;
for (int i = fs[k]; i; i = nt[i]) {
int p = dt[i];
if (p != fa) dfs(p, k), sz[k] += sz[p];
}
}

struct node {
LL v, t;
};

vector tag[N][32];
int le[N][32], now[N][32], d[N], u1[N], u2[N], ts[N];

void ins(int k, int s, int ti) {
if (!s || !k) return;
int v = s;
for (int c = 0; v; c++) {
int vl = (f[k]) ? v - (v >> 2) : v;
if (le[k][c] == 0) tag[k][c].push_back((node){vl, ti});
else tag[k][c].push_back((node){vl + tag[k][c][le[k][c] - 1].v, ti});
le[k][c]++;
v >>= 1;
}
ins(f[k], s >> 1, ti);
}

LL query(int k, int ti) {
LL s = 0;
for (int p = 0; p <= 31 && k; k = f[k], p++) {
while (now[k][p] while (now[k][p] > 0 && tag[k][p][now[k][p]].t > ti) now[k][p]--;
if (now[k][p] }
return s;
}

void doit(int l, int r, int x, int y) {
if (x > y) return;
if (l == r) {
fo(i, x, y) ts[d[i]] = l;
return;
}
int mid = (l + r) >> 1;
u1[0] = u2[0] = 0;
fo(i, x, y) {
if (pr[d[i]] <= query(d[i], mid)) u1[++u1[0]] = d[i];
else u2[++u2[0]] = d[i];
}
fo(j, 1, u1[0]) d[x + j - 1] = u1[j];
fo(j, 1, u2[0]) d[x + u1[0] + j - 1] = u2[j];
int md = x + u1[0] - 1;
doit(l, mid, x, md);
doit(mid + 1, r, md + 1, y);
}

bool cmp(int x, int y) {
return ts[x] }

int main() {
cin >> n;
fo(i, 1, n) scanf("%d", &pr[i]);
fo(i, 1, n - 1) {
int x, y;
scanf("%d%d", &x, &y);
link(x, y), link(y, x);
}
dfs(1, 0);
int q;
cin >> q;
fo(i, 1, q) {
scanf("%d%d", &ask[i][0], &ask[i][1]);
if (ask[i][0] == 1) {
scanf("%d", &ask[i][2]);
ins(ask[i][1], ask[i][2], i);
}
}
fo(i, 1, n) d[i] = i;
doit(1, q + 1, 1, n);
sort(d + 1, d + n + 1, cmp);
for (int i = 1, j = 1; i <= q; i++) {
while (j <= n && ts[d[j]] <= i) put(dfn[d[j]]), j++;
if (ask[i][0] == 2) printf("%d\n", get(dfn[ask[i][1]] + sz[ask[i][1]] - 1) - get(dfn[ask[i][1]] - 1));
}
}

推荐阅读
  • Codeforces Round #566 (Div. 2) A~F个人题解
    Dashboard-CodeforcesRound#566(Div.2)-CodeforcesA.FillingShapes题意:给你一个的表格,你 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 深入解析:手把手教你构建决策树算法
    本文详细介绍了机器学习中广泛应用的决策树算法,通过天气数据集的实例演示了ID3和CART算法的手动推导过程。文章长度约2000字,建议阅读时间5分钟。 ... [详细]
  • 在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用C语言实现小写金额转换为大写金额的方法,确保数据的标准化和规范化。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 本实验主要探讨了二叉排序树(BST)的基本操作,包括创建、查找和删除节点。通过具体实例和代码实现,详细介绍了如何使用递归和非递归方法进行关键字查找,并展示了删除特定节点后的树结构变化。 ... [详细]
  • 本题涉及一棵由N个节点组成的树(共有N-1条边),初始时所有节点均为白色。题目要求处理两种操作:一是改变某个节点的颜色(从白变黑或从黑变白);二是查询从根节点到指定节点路径上的第一个黑色节点,若无则输出-1。 ... [详细]
  • 在 Flutter 开发过程中,开发者经常会遇到 Widget 构造函数中的可选参数 Key。对于初学者来说,理解 Key 的作用和使用场景可能是一个挑战。本文将详细探讨 Key 的概念及其应用场景,并通过实例帮助你更好地掌握这一重要工具。 ... [详细]
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
author-avatar
许雅惠嘉文意芝
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有