线段树 POJ 3468

这周学习了一下线段树,偶遇POJ 3468,这道题是线段树区间更新,题意大概是有一段的长为n的数组,经过若干次对其中某一段的数进行加减,询问某一段的和。这题还是比较明显的线段树,如果细分到对每一个节点进行操作的话,复杂度为O(m^logn),容易超时,所以采取延迟标记的做法,直接对某一段进行操作,而暂不对其子树进行操作,话不多说,直接上代码吧

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include <iostream>
#include<algorithm>
#include<cmath>
using  namespace  std; 

struct node
{
    int x,y,sign;
    long long sum,ad;
} ;

node tree[400010];
long long v[100010];

long long maketree(int x,int y,int z)
{
    tree[z].x=x;
    tree[z].y=y;
    if(x>=y) return tree[z].sum=v[x];
    else return tree[z].sum=maketree(x,(x+y)/2,2*z)+maketree((x+y)/2+1,y,2*z+1);
}

void down(int q)
{
    tree[q].sign=0;
    tree[2*q].sign=tree[2*q+1].sign=1;
    tree[2*q].ad+=tree[q].ad;
    tree[2*q+1].ad+=tree[q].ad;
    tree[2*q].sum+=tree[q].ad*(tree[2*q].y-tree[2*q].x+1);
    tree[2*q+1].sum+=tree[q].ad*(tree[2*q+1].y-tree[2*q+1].x+1);
    tree[q].ad=0;
}

void add(int x,int y,int z,int q)
{
    if(x<=tree[q].x&&y>=tree[q].y)
    {
        tree[q].sign=1;
        tree[q].sum+=z*(tree[q].y-tree[q].x+1);
        tree[q].ad+=z;
        return ;
    }
    if(tree[q].sign==1) down(q);
    if(x<=(tree[q].x+tree[q].y)/2) add(x,y,z,2*q);
    if(y>=(tree[q].x+tree[q].y)/2+1) add(x,y,z,2*q+1);
    tree[q].sum=tree[2*q].sum+tree[2*q+1].sum;
    return;
}

long long find(int x,int y,int q)
{
    if(x>tree[q].y||y<tree[q].x) return 0;
    if(x<=tree[q].x&&y>=tree[q].y) return tree[q].sum;
    if(tree[q].sign==1) down(q);
    return find(x,y,2*q)+find(x,y,2*q+1);
}

int main()
{
    int n,q,x,y,z,i,k;
    long long sum;
    char ch;
    scanf("%d%d",&n,&q);
    memset(tree,0,sizeof(tree));
    for(k=1;k<=n;k++)
    {
        scanf("%lld",&v[k]);
    }
    maketree(1,n,1);
    for(i=1;i<=q;i++)
    {
        scanf("%*c%c",&ch);
        if(ch==‘C‘)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z,1);
        }
        else if(ch==‘Q‘)
        {
            scanf("%d%d",&x,&y);
            sum=find(x,y,1);
            printf("%lld\n",sum);
        }
    }
    return 0;
}
时间: 2024-10-12 11:06:46

线段树 POJ 3468的相关文章

线段树 POJ 3468 A Simple Problem with Integers

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. In

每次输出有几条线段能完全覆盖大于自己和hdu5372相反 树状数组或线段树 poj 2481 Cows

http://poj.org/problem?id=2481 Cows Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 14762   Accepted: 4886 Description Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one

两边点连直线求交点总数 树状数组或线段树 poj 3067 Japan

http://poj.org/problem?id=3067 Japan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 23602   Accepted: 6369 Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island

离散化+线段树 POJ 3277 City Horizon

POJ 3277 City Horizon Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 18466 Accepted: 5077 Description Farmer John has taken his cows on a trip to the city! As the sun sets, the cows gaze at the city horizon and observe the beautiful silho

求左下角星星之和 树状数组或线段树 poj 2352 Stars

http://poj.org/problem?id=2352 Stars Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 37696   Accepted: 16419 Description Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coo

[数据结构-线段树] poj 2528

在一面墙上贴海报,贴的顺序给出了,求最后能被看到的海报数量. 纯粹的线段树模拟题. 但数据范围给了10^7,超内存了. 实际上这里用了一个小技巧,虽然墙的宽度是很大的,但海报数量只有10000,所以这10^7个数中真正用到的数很少,这样的话就只需要把没用到的数给"删去",剩下来的数从小到大映射为新的数,这样空间复杂度就大大降低了. 比如题目给的样例: 1 4 2 6 8 10 3 4 7 10   用到的数有:1 2 3 4 6 7 8 10 可以把它们映射为: 1 2 3 4 6 7

[RMQ] [线段树] POJ 3368 Frequent Values

一句话,多次查询区间的众数的次数 注意多组数据!!!! RMQ方法: 预处理 i 及其之前相同的数的个数 再倒着预处理出 i 到不是与 a[i] 相等的位置之前的一个位置, 查询时分成相同的一段和不同的一段 (RMQ) 但是要注意 to[i] 大于查询范围的情况, 以及RMQ时 x < y 的情况!! AC代码: #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib>

线段树 poj 2991

我们只要把这些向量求和,最终所指的位置就是终点,因此我们只要维护好向量的区间和就可以了.对于第二个问题,我们可以用一个数组degree[i]表示第i个向量和第i-1一个向量当前的夹角,这样就有了当前的状态,每次读入操作后就会方便的得到相当于进行旋转多少角度的操作了,然后再更新一下degree[i]即可.并且我们每读入一个操作只会影响一个degree[]的值,不会影响到其他的degree[]. 总而言之,我们要把每个线段看成一个向量,并维护这些向量的区间和,同时要实现对区间中每个元素都加上一个值这

[qbzt寒假]线段树和树状数组

树状数组 \(lowbit(x)=x\&(-x)\) 二维树状数组 修改某个点,查询(1,1)到(n,m)的前缀和(树状数组要从1开始) HDU2642 Stars \(YFF\)是个浪漫的人,他喜欢数天上的星星. 为了解决这个问题,我们考虑到天空是一个二维平面,有时星星会很亮,有时星星会很暗.首先,天空中没有明亮的星星,然后一些信息会被给出为"\(B\) \(x\) \(y\)",其中"\(B\)"表示明亮,\(x\)表示\(x\)坐标,\(y\)表示在\