HDU 6464 /// 權值線段樹

題目大意:c++

共Q次操做 操做有兩種ide

操做一 在序列尾部加入f[i]個s[i]spa

操做二 查詢序列第f[i]小到第s[i]小之間的總和code

 

離線操做 把序列內的值離散化blog

而後利用離散化後的值 在線段樹上對應權值操做it

權值線段樹維護權值對應的值的個數和總和event

查詢 用s[i]的前綴和減去f[i]-1的前綴和 具體看註釋class

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define INF 0x3f3f3f3f
#define mem(i,j) memset(i,j,sizeof(i))
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define gcd(i,j) __gcd(i,j);
const int N=1e5+5;
const int mod=1000000007;

LL p[N], f[N], s[N];
LL cop[N], tot;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
LL num[N<<2], sum[N<<2];
void pushUp(int rt) {
    num[rt]=num[rt<<1]+num[rt<<1|1];
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod;
}
void update(LL ind,LL k,int l,int r,int rt) {
    if(l==r) {
        num[rt]+=k; // 這個值在序列內的個數
        sum[rt]=(sum[rt]+cop[ind]*k)%mod; // 總和
        return ;
    }
    int m=(l+r)>>1;
    if(m>=ind) update(ind,k,lson);
    else update(ind,k,rson);
    pushUp(rt);
}
LL query(LL k,int l,int r,int rt) {
    if(k==0) return 0;
    if(l==r) return k*cop[l]%mod; 
    // 在l位置 還差k個 k可能不須要num[l]那麼多 
    // 因此應該是k*cop[l] 而不是sum[l]
    int m=(l+r)>>1, L=rt<<1;
    if(num[L]<=k) return (sum[L]+query(k-num[L],rson))%mod;
    // 左兒子區間不足k個 那麼左兒子區間的總和+右兒子區間差的個數的總和
    else return query(k,lson);
    // 左兒子區間的數已超過k個 就在左兒子區間內繼續縮小
}

int main()
{
    mem(num,0LL); mem(sum,0LL);
    int q; scanf("%d",&q);
    inc(i,1,q) scanf("%lld%lld%lld",&p[i],&f[i],&s[i]);
    tot=0;
    inc(i,1,q) if(p[i]==1)
        cop[++tot]=s[i];
    sort(cop+1,cop+1+tot);
    tot=unique(cop+1,cop+1+tot)-cop-1;
    inc(i,1,q) {
        if(p[i]==1) {
            int ind=lower_bound(cop+1,cop+1+tot,s[i])-cop;
            update(ind,f[i],1,tot,1); // 離散化後的值在對應權值位置操做
        }
        else {
            LL R=query(s[i],1,tot,1);
            LL L=query(f[i]-1,1,tot,1);
            printf("%lld\n",(R-L+mod)%mod); 
        }
    }

    return 0;
}

 
View Code
相關文章
相關標籤/搜索