传送门
和Gty的二逼妹子序列那道题是一样的,只不过多加了一问而已
对权值分块,然后将区间离线之后莫队,每一次修改 O(1) ,查询 O(n√)
#include
#include
#include
#include
#include
using namespace std;
#define N 1000005
int n,m,block,t,ansum,ansval,ans[N][2];
int a[N],num[N],L[N],R[N],cnt[N],sum[N],val[N];
struct data{int l,r,x,y,id;}q[N];
int cmp(data a,data b)
{
return num[a.l]int l,int r,int f)
{
for (int i=l;i<=r;++i)
{
int last=cnt[a[i]];
sum[num[a[i]]]-=cnt[a[i]];
cnt[a[i]]+=f;
sum[num[a[i]]]+=cnt[a[i]];
if (!last&&cnt[a[i]]) ++val[num[a[i]]];
else if (last&&!cnt[a[i]]) --val[num[a[i]]];
}
}
void query(int l,int r)
{
ansum=0,ansval=0;
if (num[l]==num[r])
{
for (int i=l;i<=r;++i)
if (cnt[i]) ansum+=cnt[i],++ansval;
return;
}
if (l==L[num[l]]) l=num[l];
else
{
for (int i=l;i<=R[num[l]];++i)
if (cnt[i]) ansum+=cnt[i],++ansval;
l=num[l]+1;
}
if (r==R[num[r]]) r=num[r];
else
{
for (int i=L[num[r]];i<=r;++i)
if (cnt[i]) ansum+=cnt[i],++ansval;
r=num[r]-1;
}
for (int i=l;i<=r;++i) ansum+=sum[i],ansval+=val[i];
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
for (int i=1;i<=m;++i)
{
scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].x,&q[i].y);
q[i].x=max(q[i].x,1);q[i].y=min(q[i].y,n);
q[i].id=i;
}
block=sqrt(n);t=(n-1)/block+1;
for (int i=1;i<=n;++i) num[i]=(i-1)/block+1;
L[1]=1,R[1]=block;
for (int i=2;i<=n;++i) L[i]=L[i-1]+block,R[i]=R[i-1]+block;R[t]=n;
sort(q+1,q+m+1,cmp);
modui(q[1].l,q[1].r,1);
query(q[1].x,q[1].y);
ans[q[1].id][0]=ansum,ans[q[1].id][1]=ansval;
for (int i=2;i<=m;++i)
{
if (q[i-1].l<q[i].l) modui(q[i-1].l,q[i].l-1,-1);
else modui(q[i].l,q[i-1].l-1,1);
if (q[i-1].r<q[i].r) modui(q[i-1].r+1,q[i].r,1);
else modui(q[i].r+1,q[i-1].r,-1);
query(q[i].x,q[i].y);
ans[q[i].id][0]=ansum,ans[q[i].id][1]=ansval;
}
for (int i=1;i<=m;++i) printf("%d %d\n",ans[i][0],ans[i][1]);
}