kuangbin专题七 HDU1698 Just a Hook (区间设值 线段树)

In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.



Now Pudge wants to do some operations on the hook.

Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:

For each cupreous stick, the value is 1.
For each silver stick, the value is 2.
For each golden stick, the value is 3.

Pudge wants to know the total value of the hook after performing the operations.
You may consider the original hook is made up of cupreous sticks.

InputThe input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.
OutputFor each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.
Sample Input

1
10
2
1 5 2
5 9 3

Sample Output

Case 1: The total value of the hook is 24.


将一段区间设置为同一个数,然后区间求和。自己敲得时候,还是发现了一点细节问题。这个和修改有区别,pushdown的左右孩子的sum是= 而不是 += 可以理解
还有最重要的一点!!! 以后的lazy还是不要直接写了,应该先判断一下,就因为这个,找了好长时间bug


还有一个问题是 区间求和时的 Pushdown和Pushup 不是必要的???不是太懂。



  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <math.h>
  4 #include <string.h>
  5 #include <stdlib.h>
  6 #include <string>
  7 #include <vector>
  8 #include <set>
  9 #include <map>
 10 #include <queue>
 11 #include <algorithm>
 12 #include <sstream>
 13 #include <stack>
 14 using namespace std;
 15 #define FO freopen("in.txt","r",stdin);
 16 #define rep(i,a,n) for (int i=a;i<n;i++)
 17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
 18 #define pb push_back
 19 #define mp make_pair
 20 #define all(x) (x).begin(),(x).end()
 21 #define fi first
 22 #define se second
 23 #define SZ(x) ((int)(x).size())
 24 #define debug(x) cout << "&&" << x << "&&" << endl;
 25 #define lowbit(x) (x&-x)
 26 #define mem(a,b) memset(a, b, sizeof(a));
 27 typedef vector<int> VI;
 28 typedef long long ll;
 29 typedef pair<int,int> PII;
 30 const ll mod=1000000007;
 31 const int inf = 0x3f3f3f3f;
 32 ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
 33 ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
 34 //head
 35 
 36 const int maxn=100010;
 37 int sum[maxn<<2],lazy[maxn<<2],_,n,q,l,r,val;
 38 
 39 void Pushup(int rt) {
 40     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 41 }
 42 
 43 void Pushdown(int rt,int x) {
 44     if(lazy[rt]) {//!!!
 45         lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
 46         sum[rt<<1]=(x-(x>>1))*lazy[rt];//!!! =
 47         sum[rt<<1|1]=(x>>1)*lazy[rt];
 48         lazy[rt]=0;
 49     }
 50 }
 51 
 52 void build(int rt,int L,int R) {
 53     lazy[rt]=0;
 54     if(L==R) {
 55         sum[rt]=1;
 56         return;
 57     }
 58     int mid=(L+R)>>1;
 59     build(rt<<1,L,mid);
 60     build(rt<<1|1,mid+1,R);
 61     Pushup(rt);
 62 }
 63 
 64 void Updata(int rt,int L,int R,int l,int r) {
 65     if(L>=l&&R<=r) {//核心
 66         lazy[rt]=val;
 67         sum[rt]=(R-L+1)*val;
 68         return;
 69     }
 70     Pushdown(rt,R-L+1);
 71     int mid=(L+R)>>1;
 72     if(l<=mid) Updata(rt<<1,L,mid,l,r);
 73     if(r>mid) Updata(rt<<1|1,mid+1,R,l,r);
 74     Pushup(rt);
 75 }
 76 
 77 int Query(int rt,int L,int R,int l,int r) {
 78     if(L>=l&&R<=r) return sum[rt];
 79     Pushdown(rt,R-L+1);
 80     int ans=0;
 81     int mid=(L+R)>>1;
 82     if(l<=mid) ans+=Query(rt<<1,L,mid,l,r);
 83     if(r>mid) ans+=Query(rt<<1|1,mid+1,R,l,r);
 84     Pushup(rt);
 85     return ans;
 86 
 87 }
 88 
 89 int main() {
 90     int cur=1;
 91     for(scanf("%d",&_);_;_--) {
 92         scanf("%d",&n);
 93         build(1,1,n);
 94         scanf("%d",&q);
 95         while(q--) {
 96             scanf("%d%d%d",&l,&r,&val);
 97             Updata(1,1,n,l,r);
 98         }
 99         printf("Case %d: The total value of the hook is %d.\n",cur++,Query(1,1,n,1,n));
100     }
101 }

 




转载于:https://www.cnblogs.com/ACMerszl/p/9862235.html

<think>好的,我需要帮助用户了解Kuangbin的划分树相关资料或教程。首先,我要明确划分树的基本概念,确保自己理解正确。划分树是一种基于线段树的数据结构,主要用于解决区间第K小查询问题。它的核心思想是将区间递归划分,并在每个节点保存排序后的子区间,从而快速定位目标。 接下来,我需要查阅用户提供的引用内容,看看是否有相关引用可以支持回答。引用[1]提到树链剖分,虽然不直接相关,但可能涉及树结构的处理。引用[2]和[3]讨论了树状数组和线段树在树结构中的应用,这可能与划分树的空间复杂度或实现细节有关。引用[4]关于Tarjan算法,可能与划分树的应用场景不同,暂时不考虑。 然后,我需要组织回答结构。用户希望了解Kuangbin的划分树实现,可能包括算法原理、实现步骤、代码示例以及复杂度分析。根据系统级指令,要使用正确的中文和LaTeX格式,例如数学表达式用$...$,独立公式用$$...$$。 考虑到用户可能需要代码示例,我需要编写Python或伪代码来展示划分树的构建和查询过程。同时,要确保引用相关文献,比如引用[3]提到的线段树家族处理子链的能力,可能在划分树的优化中有所体现。 另外,用户要求生成相关问题,我需要围绕划分树的应用、优化、复杂度等方面提出问题。例如,划分树与其他数据结构(如线段树)的区别,或者如何处理动态数据等。 最后,检查所有LaTeX语法是否正确,如区间划分的数学表达式是否正确使用$符号,代码块是否用三个反引号标注,引用标识是否自然添加在相关段落末尾。确保回答结构清晰,分步骤解释划分树的原理和实现,帮助用户逐步理解。</think>### Kuangbin划分树详解 划分树(Partition Tree)是一种基于线段树的扩展数据结构,主要用于解决**静态区间第K小查询**问题。其核心思想是将区间递归划分,并在每个节点保存排序后的子区间信息,利用二分思想快速定位目标。 #### 一、算法原理 1. **预处理阶段**: - 将原始数组$[a_1,a_2,...,a_n]$排序得到$sorted\_arr$ - 递归地将当前区间划分为左右子区间: $$left\_part = [sorted\_arr中前mid个元素]$$ $$right\_part = [sorted\_arr中剩余元素]$$ - 记录每个元素在划分过程中进入左子区间的次数(通过`to_left`数组) 2. **查询阶段**: - 根据当前节点的划分信息,判断目标在左/右子区间 - 通过`to_left`数组快速计算子区间内的元素数量 #### 二、代码实现(Python示例) ```python class PartitionTree: def __init__(self, arr): self.n = len(arr) self.tree = [] self.to_left = [] sorted_arr = sorted(arr) self.build(0, 0, self.n-1, arr, sorted_arr) def build(self, depth, l, r, arr, sorted_arr): if l == r: if len(self.tree) <= depth: self.tree.append([]) self.to_left.append([0]*(self.n+1)) self.tree[depth].append(arr[l]) return # 划分过程(关键步骤) mid = (l + r) // 2 median = sorted_arr[mid] # 统计进入左子树的元素数量[^3] to_left = 0 left_part, right_part = [], [] for num in arr[l:r+1]: if num < median or (num == median and to_left <= mid - l): left_part.append(num) to_left += 1 else: right_part.append(num) # 合并左右部分 merged = left_part + right_part # 存储当前层数据 if len(self.tree) <= depth: self.tree.append([]) self.to_left.append([0]*(self.n+1)) self.tree[depth][l:r+1] = merged self.to_left[depth][l] = 0 cnt = 0 for i in range(l, r+1): if merged[i-l] < median or (merged[i-l] == median and cnt <= mid - l): cnt += 1 self.to_left[depth][i+1] = cnt # 递归构建子树 self.build(depth+1, l, mid, merged[:mid-l+1], sorted_arr) self.build(depth+1, mid+1, r, merged[mid-l+1:], sorted_arr) ``` #### 三、复杂度分析 - 预处理时间复杂度:$O(n \log n)$ - 查询时间复杂度:$O(\log n)$ - 空间复杂度:$O(n \log n)$(与线段树的空间消耗类似)[^2] #### 四、应用场景 1. 静态区间第K小查询(如OJ题目POJ2104) 2. 高维空间最近邻搜索的降维处理 3. 数据压缩中的分块编码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值