值域線段樹

題目鏈接
題目可轉化爲值域線段樹的寫法,題目上說讓求所有區間和的值在L到R之間的有多少個,每一個區間值可以由數組的前綴和快速求出來,設sum[i]爲i之前的和,i小於j即求sum[j]-sum[i]在L到R之間的有多少個,可以轉化爲
sum[j]-R<=sum[i]<=sum[j]-L,用sum[i]建一顆值域線段樹每次詢問在sum[j]-R到sum[j]-L之間的值有多少個累加起來就是結果。

/*
值域線段樹區間裏面存的是在這個區間內的數的個數有多少個
*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=7e6+10;
const LL inf=10000000000;
LL x[maxn];
struct AC
{
    struct zp
    {
        LL lson,rson,sum;
    } tree[maxn];
    int cnt;
    int newnode()//動態開闢節點
    {
        tree[cnt].lson=tree[cnt].rson=-1;
        tree[cnt].sum=0;
        cnt++;
        return cnt-1;
    }
    void init()
    {
        cnt=0;
    }
    void update(LL &k,LL l,LL r,LL num)//更新/插入值
    {
        if(k==-1) k=newnode();//沒有這個值新開節點
        tree[k].sum++;//這個值所處的路線上的值都加一
        if(l==r) return ;
        LL mid=(l+r)>>1;
        if(num<=mid)
            update(tree[k].lson,l,mid,num);
        else
            update(tree[k].rson,mid+1,r,num);
    }
    LL query(LL k,LL l,LL r,LL ql,LL qr)//查詢區間內有多少個值
    {
        if(k==-1) return 0;
        if(l==ql&&r==qr)
            return tree[k].sum;
        LL mid=(l+r)>>1;
        if(qr<=mid)
            return query(tree[k].lson,l,mid,ql,qr);
        else if(ql>mid)
            return query(tree[k].rson,mid+1,r,ql,qr);
        else
            return query(tree[k].lson,l,mid,ql,mid)+query(tree[k].rson,mid+1,r,mid+1,qr);
    }
} ac;
int main()
{
    LL n,L,R;
    while(~scanf("%lld%lld%lld",&n,&L,&R))
    {
        ac.init();//注意初始化
        scanf("%lld",&x[0]);
        for(int i=1; i<n; i++)
            scanf("%lld",&x[i]),x[i]+=x[i-1];
        LL root=-1;
        ac.update(root,-inf,inf,0);//先插入0,因爲x[0]也要算一次
        LL ans=0;
        for(int i=0; i<n; i++)
        {
            ans+=ac.query(root,-inf,inf,x[i]-R,x[i]-L);//統計答案
            ac.update(root,-inf,inf,x[i]);//將這個值插入後面要用到
        }
        printf("%lld\n",ans);
    }
}

題目鏈接

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=7e6+10;
const LL inf=10000000000;
struct AC
{
    struct zp
    {
        int  lson,rson;
        LL sum;
        bool lazy;
    } tree[maxn];
    int cont;
    void init()
    {
        cont=0;
    }
    int newnode()
    {
        tree[cont].lson=tree[cont].rson=-1;
        tree[cont].sum=0;
        tree[cont].lazy=0;
        cont++;
        return cont-1;
    }
    void pushdown(int k)
    {
        if(tree[k].lazy==1)
        {
            if(tree[k].lson!=-1)
            {
                tree[tree[k].lson].lazy=1;
                tree[tree[k].lson].sum=0;
            }
            if(tree[k].rson!=-1)
            {
                tree[tree[k].rson].lazy=1;
                tree[tree[k].rson].sum=0;
            }
            tree[k].lazy=0;
        }
    }
    void pushup(int k)
    {
        LL ans=0;
        if(tree[k].lson!=-1)
            ans+=tree[tree[k].lson].sum;
        if(tree[k].rson!=-1)
            ans+=tree[tree[k].rson].sum;
        tree[k].sum=ans;
    }
    void update1(int &k,LL l,LL r,LL num,LL cnt)//opt 1
    {
        if(k==-1) k=newnode();
        pushdown(k);
        tree[k].sum+=cnt;
        if(l==r) return ;
        LL mid=(l+r)>>1;
        if(num<=mid) update1(tree[k].lson,l,mid,num,cnt);
        else update1(tree[k].rson,mid+1,r,num,cnt);
    }
    void update2(int k,LL l,LL r,LL ql,LL qr)//設置清空標記
    {
        if(k==-1) return ;
        pushdown(k);
        if(ql==l&&qr==r)
        {
            tree[k].lazy=1,tree[k].sum=0;
            return ;
        }
        LL mid=(l+r)>>1;
        if(qr<=mid) update2(tree[k].lson,l,mid,ql,qr);
        else if(ql>mid) update2(tree[k].rson,mid+1,r,ql,qr);
        else
        {
            update2(tree[k].lson,l,mid,ql,mid);
            update2(tree[k].rson,mid+1,r,mid+1,qr);
        }
        pushup(k);
    }
    LL query(int k,LL l,LL r,LL ql,LL qr)//查詢區間值
    {
        if(k==-1) return 0;
        pushdown(k);
        if(l==ql&&r==qr) return tree[k].sum;
        LL mid=(l+r)>>1;
        if(qr<=mid) return query(tree[k].lson,l,mid,ql,qr);
        else if(ql>mid) return query(tree[k].rson,mid+1,r,ql,qr);
        else return query(tree[k].lson,l,mid,ql,mid)+query(tree[k].rson,mid+1,r,mid+1,qr);
    }
    LL query1(int k,LL l,LL r,LL num)//查詢第num小的數
    {
        pushdown(k);
        if(l==r) return l;
        LL mid=(l+r)>>1;
        if(tree[k].lson!=-1)
        {
            if(tree[tree[k].lson].sum>=num)
                return query1(tree[k].lson,l,mid,num);
            else
                return query1(tree[k].rson,mid+1,r,num-tree[tree[k].lson].sum);
        }
        else
            return query1(tree[k].rson,mid+1,r,num);
    }
} ac;
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        ac.init();
        int root=-1;
        for(int i=0; i<n; i++)
        {
            int opt;
            LL num,sum;
            scanf("%d%lld",&opt,&num);
            switch(opt)
            {
            case 1:
                ac.update1(root,-inf,inf,num,1);
                break;
            case 2:
                sum=ac.query(root,-inf,inf,-inf,num-1);
                ac.update2(root,-inf,inf,-inf,num-1);
                ac.update1(root,-inf,inf,num,sum);
                break;
            case 3:
                sum=ac.query(root,-inf,inf,num+1,inf);
                ac.update2(root,-inf,inf,num+1,inf);
                ac.update1(root,-inf,inf,num,sum);
                break;
            case 4:
                printf("%lld\n",ac.query1(root,-inf,inf,num));
                break;
            case 5:
                printf("%lld\n",ac.query(root,-inf,inf,-inf,num-1));
                break;
            }
        }
    }
}
發佈了110 篇原創文章 · 獲贊 18 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章