离散化+线段树

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6464

分析:

每次1操作会往序列底加first个second,first 和 second 都是最大1e9的数据,每次2操作询问序列中第first到第second个数的和

一开始就感觉有点像线段树,输入数据太大我们可以离线处理把数据离散化下,然后扔到线段树上,维护两个数组:

sum: 区间数的值的和  num: 区间数的数量和  ,对于每次询问的first和second,我们找到第first个和第second个分别是哪两个数字,

如果两个数字不相同,那么就先算出分别取了多少个这两个数字,对于两个数字中间的数字和我们可以直接用线段树区间求和得到

Ac code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100001;
const ll mod=1e9+7;
struct Node{
    ll x,y;
};
Node a[maxn];
int op[maxn];
ll b[maxn],sum[maxn<<2],num[maxn<<2],vis[maxn];
void update(ll pos,ll val,ll l,ll r,ll rt)
{
    if(l==r){
        sum[rt]=(sum[rt]+(b[pos]*val)%mod)%mod;
        num[rt]+=val;
        return;
    }
    ll mid=(l+r)>>1;
    if(pos<=mid) update(pos,val,l,mid,rt<<1);
    else update(pos,val,mid+1,r,rt<<1|1);
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod;
    num[rt]=num[rt<<1]+num[rt<<1|1];
}
ll query(ll L,ll R,ll l,ll r,ll rt)///区间查询[L,R]的数的值的和
{
    if(L<=l&&r<=R){
        return sum[rt]%mod;
    }
    ll mid=(l+r)>>1;
    ll ans=0;
    if(L<=mid) ans=(ans+query(L,R,l,mid,rt<<1))%mod;
    if(mid<R) ans=(ans+query(L,R,mid+1,r,rt<<1|1))%mod;
    return ans;
}
ll query1(ll pos,ll l,ll r,ll rt)///查询pos位于b数组的哪个位置
{
    if(num[rt]>=pos&&num[rt]-vis[r]<pos)///说明第pos小的数是b[r]
         return r;
    ll mid=(l+r)>>1;
    if(pos<=num[rt<<1]) query1(pos,l,mid,rt<<1);
    else  query1(pos-num[rt<<1],mid+1,r,rt<<1|1);
}
ll query2(ll L,ll R,ll l,ll r,ll rt)///求区间[L,R]有多少个数字
{
    if(L<=l&&r<=R)
        return num[rt];
    ll mid=(l+r)>>1;
    ll ans=0;
    if(L<=mid) ans=(ans+query2(L,R,l,mid,rt<<1));
    if(mid<R) ans=(ans+query2(L,R,mid+1,r,rt<<1|1));
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    int k=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%lld%lld",&op[i],&a[i].x,&a[i].y);
        if(op[i]==1) b[++k]=a[i].y;
    }

    sort(b+1,b+1+k);///离散化处理
    for(int i=1;i<=n;i++){
        if(op[i]==1){
            ll id=lower_bound(b+1,b+1+k,a[i].y)-b;
            update(id,a[i].x,1,k,1);
            vis[id]+=a[i].x;
        }
        else{
            ll l=query1(a[i].x,1,k,1);
            ll r=query1(a[i].y,1,k,1);

            ll ans=0;
            if(l==r)
                ans=b[l]*(a[i].y-a[i].x+1)%mod;
            else{

                ll l=query1(a[i].x,1,k,1);
                ll r=query1(a[i].y,1,k,1);
                ll k1=((query2(1,l,1,k,1)-a[i].x+1+mod)%mod)*b[l]%mod///l剩余的
                ll k2=((a[i].y-query2(1,r-1,1,k,1)+mod)%mod)*b[r]%mod;///r剩余的
                ll k0=query(l+1,r-1,1,k,1)%mod;///[l+1,r-1]整段区间的
                ans=(k0+k1+k2)%mod;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shaohang_/article/details/88643105
今日推荐