bzoj4627: [BeiJing2016]回转寿司

权值线段树。

要求 L<=(s[i]-s[j])<=R  (i<j)。 的i和j的数量。

所以把前缀和s加入一棵权值线段树,每次询问满足条件的范围中的权值的个数。

权值线段树不能像普通线段树一样预处理,否则因为权值范围过大会爆掉。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long 
using namespace std;
const LL inf = 10000000000ll;
const int maxn = 100000 + 10;
const int maxm = 8000000 + 10;

struct segtree {
    LL l[maxm],r[maxm];
    int lc[maxm],rc[maxm];
    int v[maxm],vid;
    
    void change(int &x,LL L,LL R,LL p) {
        if(!x) {x=++vid;l[x]=L;r[x]=R;}
        v[x]++;
        if(L==R) return;
        LL mid=(L+R)>>1;
        if(p<=mid) change(lc[x],L,mid,p);
        else change(rc[x],mid+1,R,p);    
    }
    
    int ask(int x,LL L,LL R) {
        if(!x) return 0;
        if(r[x]<L || l[x]>R) return 0;
        if(L<=l[x]&&r[x]<=R) return v[x];
        return ask(lc[x],L,R)+ask(rc[x],L,R);
    }
        
}seg;

int root;
LL res=0,n,L,R;

int main() {
    LL s=0;
    scanf("%lld%lld%lld",&n,&L,&R);
    for(int i=1,x;i<=n;i++) {
        scanf("%d",&x);        
        seg.change(root,-inf,inf,s);
        s+=x;
        res+=seg.ask(root,max(-inf,s-R),min(inf,s-L));
    }
    printf("%lld\n",res);
    return 0;    
}

posted @ 2016-07-11 17:11  invoid  阅读(372)  评论(0编辑  收藏  举报