Loading

P4556 题解

P4556 题解

这道题一开始读错题了,导致思路走偏。

考虑到编号是一段区间,我们立马就可以想到主席树来做,不难发现一定是左边的人往右边跑,右边的人往左边跑,所以我们相当于是要在线段树上去二分一个分界点,这是因为我们一定可以找到一个最优方案,这些编号先对位置没有变化。

具体来说,我们建立一棵主席树,然后考虑,向右边跑的和向左边跑的两边的贡献,我们在主席树上二分,当左右两边都往同一个方向跑的时候,我们计算答案,否则我们继续往下递归。如果当前区间里面已经没有数了,我们也停止递归。

然后我们来考虑一下如何计算答案,不难发现,答案的形式实际上是区间和和等差数列,所以我们直接硬做就可以了。

时间复杂度大概是二分一个分界点的复杂度,可以接受。

代码:


#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define int long long
#define uint unsigned int
#define ull unsigned long long
#define N 20000000
#define M number
using namespace std;

const int INF=0x3f3f3f3f;
const int len=1000000;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

struct Node{
    int ls,rs,Size,sum;
    inline Node(){}
    inline Node(int ls,int rs,int Size,int sum) : ls(ls),rs(rs),Size(Size),sum(sum) {}
}p[N];

int tot,root[N],n,m,a[N];

#define ls(k) p[k].ls
#define rs(k) p[k].rs
struct SegmentTree{
    inline void PushUp(int k){
        p[k].sum=p[ls(k)].sum+p[rs(k)].sum;
        p[k].Size=p[ls(k)].Size+p[rs(k)].Size;
    }
    inline void Insert(int &k,int last,int l,int r,int w,int val){
        k=++tot;p[k]=p[last];
        if(l==r){p[k].sum+=w;p[k].Size++;return;}int mid=(l+r)>>1;
        if(w<=mid) Insert(ls(k),ls(last),l,mid,w,val);
        else Insert(rs(k),rs(last),mid+1,r,w,val);
        PushUp(k);
    }
    inline int Solve(int lk,int rk,int k,int l,int r,int rank){
        int nowsize=p[rk].Size-p[lk].Size,nowsum=p[rk].sum-p[lk].sum;
        // printf("lk=%d rk=%d k=%d l=%d r=%d rank=%d\n",lk,rk,k,l,r,rank);
        if(nowsize==0||nowsum==0) return 0;int mid=(l+r)>>1;
        if(l<=k+rank-1&&r<=k+rank+nowsize-2) return (2*k+2*rank+nowsize-3)*(nowsize)/2-nowsum;
        else if(l>=k+rank-1&&r>=k+rank+nowsize-2) return nowsum-(2*k+2*rank+nowsize-3)*(nowsize)/2;
        else return Solve(ls(lk),ls(rk),k,l,mid,rank)+Solve(rs(lk),rs(rk),k,mid+1,r,rank+p[ls(rk)].Size-p[ls(lk)].Size);
    }
}tr;

signed main(){
    // freopen("my.in","r",stdin);
    // freopen("my.out","w",stdout);
    read(n);read(m);
    for(int i=1;i<=n;i++){
        read(a[i]);tr.Insert(root[i],root[i-1],1,len,a[i],1);
    }
    for(int i=1;i<=m;i++){
        int l,r,k;read(l);read(r);read(k);
        printf("%lld\n",tr.Solve(root[l-1],root[r],k,1,len,1));
    }
    return 0;
}

posted @ 2022-01-22 16:26  hyl天梦  阅读(73)  评论(0编辑  收藏  举报