LOJ.#6468. 魔法[差分+树状数组]

题意

题目链接

分析

  • 将询问差分并不断加入颜色。

  • 每种颜色,一个位置 \(p\) 都只会走到与之左右相邻的两个位置之一,分类讨论 \(\rm |A-B|\) 的符号。

  • 实现可以使用树状数组。

  • 总时间复杂度为 \(O(nlogn)\)

代码

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi() {
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)) {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(isdigit(ch)) {
        x=(x<<3)+(x<<1)+ch-48;
        ch=getchar();
    }
    return x*f;
}
template<typename T>inline bool Max(T &a,T b) {
    return a<b?a=b,1:0;
}
template<typename T>inline bool Min(T &a,T b) {
    return b<a?a=b,1:0;
}
const int N=2e5 + 7;
int n,Q;
LL ans[N];
struct querys{
    int id,p,c;
    querys(){}querys(int id,int p,int c):id(id),p(p),c(c){}
};
vector<int>G[N];
vector<querys>q[N];
struct BIT {
    LL t1[N],t2[N];
    int lowbit(int x) {
        return x&-x;
    }
    void m1(int x,int y){for(int i=x;i<=n;i+=lowbit(i)) t1[i]+=y;}
    void m2(int x,int y){for(int i=x;i<=n;i+=lowbit(i)) t2[i]+=y;}
    pair<LL,int> query(int x){
        LL r1=0;int r2=0;
        for(int i=x; i; i-=lowbit(i)) r1+=t1[i],r2+=t2[i];
        return make_pair(r1,r2);
    }
    void upd(int l,int r,int v) {
        if(l>r) return;
        m1(l,v),m1(r+1,-v);
        m2(l,1),m2(r+1,-1);
    }
} A,B;
int main(){
    n=gi(),Q=gi();
    rep(i,1,n) {
        int c=gi();
        G[c].pb(i);
    }
    
    rep(i,1,Q) {
        int p=gi(),l=gi(),r=gi();
        q[l-1].pb(querys(i,p,-1));
        q[r].pb(querys(i,p,1));
    }
    rep(i,1,n) {
        for(int j=0; j<G[i].size(); ++j) {
            if(!j)
                B.upd(1,G[i][j]-1,G[i][j]);
            if(j==(int)G[i].size()-1)
                A.upd(G[i][j],n,G[i][j]);
            else{
                int mid=(G[i][j]+G[i][j+1])/2;
                A.upd(G[i][j],mid,G[i][j]);
                B.upd(mid+1,G[i][j+1]-1,G[i][j+1]);
            }
        }
        for(auto v:q[i]) {
            pair<LL,int> ra=A.query(v.p),rb=B.query(v.p);
            ans[v.id]+=v.c*(1ll*ra.second*v.p-ra.first);
            ans[v.id]+=v.c*(rb.first-1ll*rb.second*v.p);
        }
    }
    rep(i,1,Q) printf("%lld\n",ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/yqgAKIOI/p/9878910.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值