简单线段树

一、单点更新

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]就是直接离散化出来的数组

猜你喜欢

转载自www.cnblogs.com/Cloud-king/p/9482920.html