前置知识
解法
进行差分,区间查询转化成前缀和相减。
先将 \(\{ a \}\) 升序排序。
设当前询问的区间为 \([1,r]\),在 \(\{ a \}\) 中找到一个最大的 \(pos\) 使得 \(a_{pos} \le r\),则 \([1,r]\) 中所做常规的次数为 \(\sum\limits_{i=1}^{pos}\left\lfloor \dfrac{r-a_{i}}{k} \right\rfloor\)。
考虑拆开向下取整,有 \(\begin{aligned} &\sum\limits_{i=1}^{pos}\left\lfloor \dfrac{r-a_{i}}{k} \right\rfloor \\ &=\sum\limits_{i=1}^{pos} \dfrac{r-a_{i}-(r-a_{i}) \bmod k}{k} \\ &=\dfrac{1}{k} \times \sum\limits_{i=1}^{pos}r-a_{i}-(r-a_{i}) \bmod k \\ &=\dfrac{1}{k} \times (r \times pos-\sum\limits_{i=1}^{pos}a_{i}-\sum\limits_{i=1}^{pos}(r-a_{i}) \bmod k) \end{aligned}\)。
难点在于怎么求 \(\sum\limits_{i=1}^{pos}(r-a_{i}) \bmod k\)。考虑按照取模运算的性质拆开并适当补上 \(+k\),有 \(\begin{aligned} (r-a_{i}) \bmod k=r \bmod k-a_{i} \bmod k+[r \bmod k<a_{i} \bmod k] \times k \end{aligned}\)。
以 \(a_{i} \bmod k\) 为权值建立一棵主席树然后主席树上查询 \([1,pos]\) 内满足 \(a_{i} \bmod k \in (r \bmod k,k)\) 即可。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define sort stable_sort
#define endl '\n'
ll a[100010],sum1[100010],sum2[100010];
struct PDS_SMT
{
ll root[100010],rt_sum=0;
struct SegmentTree
{
ll ls,rs,sum;
}tree[100010<<5];
#define lson(rt) tree[rt].ls
#define rson(rt) tree[rt].rs
ll build_rt()
{
rt_sum++;
return rt_sum;
}
void update(ll pre,ll &rt,ll l,ll r,ll pos)
{
rt=build_rt();
tree[rt]=tree[pre];
tree[rt].sum++;
if(l==r)
{
return;
}
ll mid=(l+r)/2;
if(pos<=mid)
{
update(lson(pre),lson(rt),l,mid,pos);
}
else
{
update(rson(pre),rson(rt),mid+1,r,pos);
}
}
ll query(ll rt,ll l,ll r,ll x,ll y)
{
if(x<=l&&r<=y)
{
return tree[rt].sum;
}
ll mid=(l+r)/2,ans=0;
if(x<=mid)
{
ans+=query(lson(rt),l,mid,x,y);
}
if(y>mid)
{
ans+=query(rson(rt),mid+1,r,x,y);
}
return ans;
}
}T;
ll ask(ll r,ll n,ll k)
{
ll ans=0,pos=upper_bound(a+1,a+1+n,r)-a-1;
ans+=r*pos;
ans-=sum1[pos];
ans-=(r%k)*pos;
ans+=sum2[pos];
ans-=T.query(T.root[pos],0,k-1,r%k+1,k-1)*k;
return ans/k;
}
int main()
{
ll type,n,m,k,mod,l,r,ans=0,i;
cin>>type>>n>>m>>k;
if(type==1)
{
cin>>mod;
}
for(i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+1+n);
for(i=1;i<=n;i++)
{
sum1[i]=sum1[i-1]+a[i];
sum2[i]=sum2[i-1]+a[i]%k;
T.update(T.root[i-1],T.root[i],0,k-1,a[i]%k);
}
cin>>l>>r;
ans=ask(r,n,k)-ask(l-1,n,k);
cout<<ans<<endl;
for(i=2;i<=m;i++)
{
cin>>l>>r;
if(type==1)
{
l=(l+ans-1)%mod+1;
r=(r+ans-1)%mod+1;
if(l>r)
{
swap(l,r);
}
}
ans=ask(r,n,k)-ask(l-1,n,k);
cout<<ans<<endl;
}
return 0;
}
标签:P6638,JYLOI,limits,题解,bmod,pos,sum,ans,ll
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18400955