简单线段树

一、单点更新

hdu1166区间和

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;
const int maxn=50005;
const int maxnnode=1<<19;
struct node{
    int value;
    int left,right;
}node[maxnnode];

int father[maxn];

void BuidTree(int i,int l,int r)
{
    node[i].left=l;
    node[i].right=r;
    node[i].value=0;
    if(l==r)
    {
        father[l]=l;
        return ;
    }
    BuidTree(i<<1,l,(int)floor((l+r)/2.0));
    BuidTree((i<<1)+1,(int)floor((l+r)/2.0+1),r);
}

void UpdataTree(int ri,int x)
{
    if(ri==1)return;
    int fi=ri/2;
    node[fi].value+=x;
    UpdataTree(fi,x);
}

int res=0;

void Query(int i,int l,int r)
{
    if(node[i].left==l&&node[i].right==r)
    {
        res+=node[i].value;
        return;
    }
    i<<1;
    if(l<=node[i].right)
    {
        if(r<=node[i].right)
            Query(i,l,r);
        else
            Query(i,l,node[i].right);
    }
    i++;
    if(r<=node[i].left)
    {
        if(l<=node[i].left)
            Query(i,l,r);
        else
            Query(i,node[i].left,r);
    }
}
int main()
{
    int t;
    cin >> t;
    while(t--){
        int n,tmp,k=1;
        cin >> n;
        BuidTree(1,1,n);
        for(int i=0;i<n;i++)
        {
            cin >> tmp;
            node[father[tmp]].value=tmp;
            UpdataTree(father[tmp],tmp);
        }
        cout << "Case " << k << ":" << endl;
        while(1)
        {
            string op;
            int a,b;
            cin >> op >> a >> b;
            if(op[0]==‘Q‘)
                Query(1,a,b);
            else if(op[0]==‘S‘)
                UpdataTree(father[a],-b);
            else if(op[0]==‘A‘)
                UpdataTree(father[a],b);
            else
                break;
        }
        k++;
    }
    return 0;
}

二、区间更新

POJ3468区间和,Lazy标记只有当操作到该节点时才将标价下放;

#include <iostream>
#include <cstdio>

using namespace std;
typedef long long ll;
const int maxn=1e5+10;

#define lson l,m,i<<1
#define rson m+1,r,i<<1|1

ll sum[maxn<<2],add[maxn<<2];        //区间和,区间结点增加值;

struct Node{
    int l,r;
    int mid(){
        return (l+r)>>1;
    }
}tree[maxn<<2];

void PushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

void PushDown(int rt,int m)
{
    if(add[rt]){                     //如果该区间结点标记存在,向下推移;
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=add[rt]*(m-(m>>1));
        sum[rt<<1|1]+=add[rt]*(m>>1);
        add[rt]=0;
    }
}

void BuidTree(int l,int r,int i)   //建树;
{
    tree[i].l=l;
    tree[i].r=r;
    add[i]=0;
    if(l==r){
        scanf("%I64d",&sum[i]);
        return;
    }
    int m=tree[i].mid();
    BuidTree(lson);
    BuidTree(rson);
    PushUp(i);
}
void UpdataTree(int c,int l,int r,int rt)
{
    if(tree[rt].l==l&&tree[rt].r==r){          //符合查询区间条件;
        add[rt]+=c;
        sum[rt]+=(ll)c*(r-l+1);
        return;
    }
    if(tree[rt].l==tree[rt].r)return;
    PushDown(rt,tree[rt].r-tree[rt].l+1);   //将标记下移;
    int m=tree[rt].mid();
    if(r<=m)UpdataTree(c,l,r,rt<<1);        //递归向下查找匹配区间;
    else if(l>m)
        UpdataTree(c,l,r,rt<<1|1);
    else{
        UpdataTree(c,l,m,rt<<1);
        UpdataTree(c,m+1,r,rt<<1|1);
    }
    PushUp(rt);
}

ll Query(int l,int r,int rt)
{
    if(l==tree[rt].l&&r==tree[rt].r)return sum[rt];
    PushDown(rt,tree[rt].r-tree[rt].l+1);
    int m=tree[rt].mid();
    ll res=0;
    if(r<=m)res+=Query(l,r,rt<<1);          //匹配合适的查找区间;
    else if(l>m)res+=Query(l,r,rt<<1|1);
    else{
        res+=Query(l,m,rt<<1);
        res+=Query(m+1,r,rt<<1|1);
    }
    return res;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        BuidTree(1,n,1);
        while(m--){
            char ch[3];
            int a,b,c;
            scanf("%s",ch);
            //cout << ch << endl;
            if(ch[0]==‘Q‘)
            {
                scanf(" %d %d",&a,&b,&c);
                printf("%lld\n",Query(a,b,1));
            }else{
                scanf(" %d %d %d\n",&a,&b,&c);
                UpdataTree(c,a,b,1);
            }
        }
    }
    return 0;
}

三、线段树+离散化

poj2528

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=20005;
const int MAX=1e7+5;
#define lson left,m,rt<<1
#define rson m+1,right,rt<<1|1
//海报从后往前贴,避免后面的海报的干扰;
int pl[maxn],pr[maxn];      //存区间端点
int port[maxn],id[MAX];     //离散化端点
bool covered[maxn<<2];      //存线段树的区间信息
struct node{
    int l,r;
    int mid(){
        return (l+r)>>1;
    }
}tree[maxn<<2];

void BuidTree(int left,int right,int rt)
{
    tree[rt].l=left;
    tree[rt].r=right;
    covered[rt]=false;
    if(left>=right)
        return ;
    int m=tree[rt].mid();
    BuidTree(lson);
    BuidTree(rson);
}

bool query(int left,int right,int rt)
{
    if(covered[rt])return false;
    if(left==tree[rt].l&&right==tree[rt].r){
        covered[rt]=true;
        return true;
    }
    int m=tree[rt].mid();
    bool res;
    if(right<=m){
        res=query(left,right,rt<<1);
    }else if(left>m){
        res=query(left,right,rt<<1|1);
    }else{
        bool res1=query(left,m,rt<<1);
        bool res2=query(m+1,right,rt<<1|1);
        res=res1||res2;
    }
    if(covered[rt<<1]&&covered[rt<<1|1])    covered[rt]=true;
    return res;
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--){
        int cnt=0,ans=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&pl[i],&pr[i]);
            port[cnt++]=pl[i];
            port[cnt++]=pr[i];
        }
        sort(port,port+cnt);
        cnt=unique(port,port+cnt)-port;     //离散化;
        for(int i=0;i<cnt;i++)  id[port[i]]=i+1;

        BuidTree(1,cnt,1);
        for(int i=n-1;i>=0;i--){
            //cout << i <<endl;
            if(query(id[pl[i]],id[pr[i]],1)){
                ans++;
                //cout << ans << endl;
            }
        }
        cout <<ans << endl;
    }
    return 0;
}

离散化:有些数据本身很大, 自身无法作为数组的下标保存对应的属性。如果这时只是需要这堆数据的相对属性, 那么可以对其进行离散化处理。当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。比如当你数据个数n很小,数据范围却很大时(超过1e9)就考虑离散化更小的值,能够实现更多的算法。

//1.用数组离散
for(int i=1;i<=n;i++){
    cin>>a[i].val;
    a[i].id = i;
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
    b[a[i].id] = i;     //将a[i]数组映射成更小的值,b[i]就是a[i]对应的rank值

//2.用STL+二分离散化
for(int i=1;i<=n;i++){
    cin>>a[i];
    b[i] = a[i];
}
sort(b+1,b+1+n);
int len = unique(b+1,b+1+n)-b-1;   //len就是去重之后的数组长度,unique用法可以去网上看看,用法简单
for(int i=1;i<=n;i++)
    a[i] = lower_bound(b+1,b+1+n,a[i])-b;   //a[i]就是直接离散化出来的数组

原文地址:https://www.cnblogs.com/Cloud-king/p/9482920.html

时间: 2024-10-02 01:39:36

简单线段树的相关文章

【简单线段树】I Hate It (求范围内最大)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 53477    Accepted Submission(s): 21005 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的

poj 3468(简单线段树区间更新)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 61936   Accepted: 18934 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

HDOJ-1754(简单线段树)

最近开始重新学习线段树,先从最简单的开始吧! I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 46762    Accepted Submission(s): 18316 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 不管

HDU 2795 Billboard(简单线段树)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 12812    Accepted Submission(s): 5578 Problem Description At the entrance to the university, there is a huge rectangular billboard of

HDU-1166 炮兵布阵 (简单线段树)

题意:给N个数,然后给出N个数对应的数值,然后对叶子结点进行add,sub,query操作 输入end时即寻问结束 思路:对于RMQ问题当然使用线段树比较方便,同时这道题也是最简单的线段树(因为只对叶子结点进行修改,而没有对区间进行修改)对结点进行sub(减)操作即使 加入一个相反数 完整题解: 别人的模板修改:(这个有区间修改) #include<iostream> #include<cstdio> #define ll long long using namespace std

士兵杀敌(三)简单线段树

题目描述 南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果. 所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少. 现在,请你写一个程序,帮小工回答南将军每次的询问吧. 注意,南将军可能询问很多次. 输入 只有一组测试数据第一行是两个整数N,Q,其中N表示士兵的总数.Q表示南将

poj 3246 简单线段树

线段树还真有点难写... #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <stack> #include <queue> using namespace std; typedef long long LL; #define oo 0x3f3f3f3f #define N 200100 struct node

2014多校10(1003)hdu4973(简单线段树区间操作)

A simple simulation problem. Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 679    Accepted Submission(s): 269 Problem Description There are n types of cells in the lab, numbered from 1 to n.

【简单线段树】敌兵布阵

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 62044    Accepted Submission(s): 26225 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营 地,Derek和Tidy的任