[loj6468]魔法——离线询问+树状数组 大佬们的博客 Some Links

题目大意:

有一个长度为 n 的序列,每一个位置有一种颜色,颜色编号为1-n。
给定q个询问,求在p点的人如果要收集[l,r]种颜色的最小代价为多少?
收集i位置的颜色的代价为abs(p-i)。

思路:

考虑每一种颜色对于每一个位置需要收集它的人的贡献。
如果这种颜色出现了多次,对于紧接着出现的两个位置i,j,如果人在[i,mid(i,j)]的话,显然收集i位置会比较好,反之则收集j位置的比较好。对于上面划分的这样一段连续的人,他们的代价显然是单调+1或者-1的,所以可以用两个树状数组来维护。
对于计算了贡献的颜色,我们显然可以求出每一个人收集这些颜色的代价,所以可以把每一个人收集的颜色[l,r]拆分成两个区间[1,l-1],[1,r],我们顺次把每一种颜色的贡献算进去,然后每一个人在两个点的时候差分一下就好了。

orz zjB_shadow

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("loj6468.in","r",stdin);
    freopen("loj6468.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=2e5+10;
int n,q,a[maxn],pos[maxn];
vector<int>col[maxn],l[maxn],r[maxn];
ll ans[maxn],sum1[maxn],sum2[maxn];

int lowbit(int x){return x&(-x);}

void modify(ll *sum,int p,ll x){while(p<=n)sum[p]+=x,p+=lowbit(p);}

ll query(ll *sum,int p){ll ret=0;while(p>=1)ret+=sum[p],p-=lowbit(p);return ret;}

void init(){
    read(n); read(q);
    REP(i,1,n)read(a[i]);
    REP(i,1,n)col[a[i]].push_back(i);
    int u,v;
    REP(i,1,q){
        read(pos[i]); read(u); read(v);
        l[u].push_back(i);
        r[v].push_back(i);
    }
}

ll get_ans(int p){return query(sum1,p)+query(sum2,p)*p;}

void work(){
    REP(i,1,n){
        int las=1;
        for(int sz=col[i].size()-1,j=0;j<=sz;++j){
            int p=col[i][j];
            modify(sum1,las,p); modify(sum1,p+1,-p);
            modify(sum2,las,-1); modify(sum2,p+1,1);
            if(j<sz)las=(col[i][j]+col[i][j+1])>>1;
            else las=n;
            modify(sum1,p,-p); modify(sum1,las+1,p);
            modify(sum2,p,1); modify(sum2,las+1,-1);
            las=las+1;
        }
        for(int sz=l[i+1].size()-1,j=0;j<=sz;++j)
            ans[l[i+1][j]]-=get_ans(pos[l[i+1][j]]);
        for(int sz=r[i].size()-1,j=0;j<=sz;++j)
            ans[r[i][j]]+=get_ans(pos[r[i][j]]);
    }
}

int main(){
    File();
    init();
    work();
    REP(i,1,q)printf("%lld\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/81782853
今日推荐