nefu 1328 区间求和(主席树+离线处理)

本文介绍如何使用主席树解决区间求和问题,通过离线处理的方式,将数的插入和区间的查询进行排序,确保高效地找到小于等于特定值的所有数的和。

区间求和

Problem:1328
Time Limit:2000ms
Memory Limit:165535K

Description

有一个序列包含n个正整数,现在有m次询问,每次询问为:求(L,R)的区间中小于等于K的数的和?

Input

输入包含多组数据。每组数据,第一行为n,表示这个整数序列长为n(1<=n<=1e5)。第二行输入整数序列x1,x2,……,xn(1<=xi<=1e9)。第三行输入m(1<=m<=1e5)。接下来m行,每行输入L,R,K(1<=L<=R<=n,0<=K<=1e9)。

Output

每组数据首先输出“Case #x:”,x从1开始,然后m行输出每次询问的结果,具体格式请参考样例。

Sample Input

6
2 5 3 4 7 6
3
2 5 4
3 6 5
1 4 3

Sample Output

Case #1:
7
7
5

Hint

Source

CJJ
题意:

中文题。

思路:

一开始想这道题,想到了莫队。然后到后来调莫队的时候发现要想调对,几乎就是暴力了。果断弃题,根本没有往主席树上想。QAQ

如果是用主席树写的话,因为K在查询是未知的,无法确定小于等于K的值都在哪一棵树上,所以需要离线处理。我们把需要插入的数和询问的区间和K值都记录下来,并按照从小到大排序。如果遇到了数,我们就插入这个值,如果遇到了询问,我们就访问最近的那棵树,访问l到r区间。最后按照询问的顺序输出就行了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
struct data
{
    int v,id,f,l,r;
}q[2*maxn];
bool cmp(data a,data b)
{
    if(a.v!=b.v)
        return a.v<b.v;
    if(a.f!=b.f)
        return a.f<b.f;
    return a.id<b.id;
}
int root[maxn],cnt,a[maxn];
long long ans[maxn];
struct node
{
    int l,r,ls,rs;
    long long sum;
}tr[maxn*30];
int build(int l,int r)
{
    int now=++cnt;
    tr[now].l=l,tr[now].r=r;
    tr[now].sum=0;
    if(l==r) return now;
    int mid=(l+r)/2;
    tr[now].ls=build(l,mid);
    tr[now].rs=build(mid+1,r);
    return now;
}
int update(int pre,int pos,int c)
{
    int now=++cnt;
    tr[now]=tr[pre];
    tr[now].sum+=(long long)c;
    int l=tr[pre].l,r=tr[pre].r;
    if(l==r) return now;
    int mid=(l+r)/2;
    if(pos<=mid) tr[now].ls=update(tr[pre].ls,pos,c);
    else tr[now].rs=update(tr[pre].rs,pos,c);
    return now;
}
long long query(int now,int x,int y)
{
    long long ans=0;
    if(now<=0) return 0;
    int l=tr[now].l,r=tr[now].r;
    if(x<=l&&r<=y)
        return tr[now].sum;
    int mid=(l+r)/2;
    if(x<=mid) ans+=query(tr[now].ls,x,y);
    if(y>mid) ans+=query(tr[now].rs,x,y);
    return ans;
}
int main()
{
    int n,cas=1,m;
    while(~scanf("%d",&n))
    {
        memset(q,0,sizeof(q));
        cnt=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            q[i].id=i,q[i].v=a[i];
            q[i].f=0;
        }
        scanf("%d",&m);
        for(int i=n+1;i<=n+m;i++)
        {
            scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].v);
            q[i].f=1;
            q[i].id=i-n;
        }
        sort(q+1,q+1+m+n,cmp);
        root[0]=build(1,n);
        int num=0;
        for(int i=1;i<=n+m;i++)
        {
            if(q[i].f==0)
            {
                num++;
                root[num]=update(root[num-1],q[i].id,q[i].v);
            }
            else
            {
                long long anss=query(root[num],q[i].l,q[i].r);
                ans[q[i].id]=anss;
            }
        }
        printf("Case #%d:\n",cas++);
        for(int i=1;i<=m;i++)
        {
            printf("%lld\n",ans[i]);
        }
    }
    return 0;
}


### 关于二叉排序二叉平衡 #### 二叉排序 (Binary Search Tree, BST) 二叉排序是一种特殊的二叉,其特性在于对于任意节点`n`而言: - `n`的左子中的所有节点的关键字均小于`n`的关键字; - `n`的右子中的所有节点的关键字均大于`n`的关键字。 这种性质使得二叉排序非常适合用于快速查找、插入以及删除操作。当构建一棵接近完全二叉形态的理想状态下的BST时,这些基本操作的时间复杂度可以达到O(log n)[^1]。 ```python class TreeNode: def __init__(self, key=None): self.key = key self.left = None self.right = None def insert(root, key): if root is None: return TreeNode(key) if key < root.key: root.left = insert(root.left, key) elif key > root.key: root.right = insert(root.right, key) return root ``` #### 二叉平衡 (Balanced Binary Tree) 为了克服普通二叉排序可能退化成链表的情况(最坏情况下时间复杂度会变为O(n)),引入了自调整机制来保持的高度尽可能低,即所谓的“平衡”。常见的实现方式包括AVL红黑等。这里以AVL为例说明如何维持的平衡属性。 每当执行一次插入或删除之后都需要检查并维护当前节点及其祖先节点之间的高度差不超过1。如果违反此条件,则通过旋转操作重新排列部分子结构从而恢复整个的平衡性。 ```python # AVL Node definition remains similar to above but with additional height attribute. class AVLNode(TreeNode): def __init__(self, key=None): super().__init__(key=key) self.height = 1 def get_height(node): if not node: return 0 return node.height def update_height(node): if node: node.height = max(get_height(node.left), get_height(node.right)) + 1 def rotate_left(z): y = z.right T2 = y.left # Perform rotation y.left = z z.right = T2 # Update heights after rotations update_height(z) update_height(y) return y def rotate_right(z): y = z.left T3 = y.right # Perform rotation y.right = z z.left = T3 # Update heights after rotations update_height(z) update_height(y) return y ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值