bzoj 3781 小B的询问——分块

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3781

非常经典的分块套路。于是时间空间比大家的莫队差了好多……

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int N=5e4+5,M=230;
int n,m,w,base,a[N],cnt[M][N],ct[N];
ll sm[M][M],ans;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
int bh(int a){return (a-1)/base+1;}
void init()
{
  int R=bh(n);
  for(int i=1;i<=R;i++)
    {
      int t=i*base,j=i;
      if(t>n)
    {
      t=(i-1)*base;
      for(int k=t+1;k<=n;k++)
        sm[i][i]+=(cnt[i][a[k]]<<1)+1,cnt[i][a[k]]++;
      j=i-1;
    }
      for(;t;j--)
    {
      sm[i][j]+=sm[i][j+1];//
      for(int k=1;k<=base;k++,t--)
        {
          sm[i][j]+=(cnt[i][a[t]]<<1)+1;
          cnt[i][a[t]]++;
        }
    }
    }
}
int main()
{
  n=rdn(); m=rdn(); w=rdn();
  base=sqrt(n);
  for(int i=1;i<=n;i++)a[i]=rdn();
  init();
  for(int i=1,l,r,u,v;i<=m;i++)
    {
      l=rdn(); r=rdn(); u=bh(l); v=bh(r);
      if(v-u<=1)
    {
      ans=0;
      for(int j=l;j<=r;j++) ct[a[j]]=0;
      for(int j=l;j<=r;j++)
        ans+=(ct[a[j]]<<1)+1,ct[a[j]]++;
      printf("%lld
",ans);continue;
    }
      ans=sm[v-1][u+1];
      int L=u*base,R=(v-1)*base;
      for(int j=l;j<=L;j++)
    {
      ans+=((cnt[v-1][a[j]]-cnt[u][a[j]])<<1)+1;
      cnt[v-1][a[j]]++;
    }
      for(int j=R+1;j<=r;j++)
    {
      ans+=((cnt[v-1][a[j]]-cnt[u][a[j]])<<1)+1;
      cnt[v-1][a[j]]++;
    }
      for(int j=l;j<=L;j++) cnt[v-1][a[j]]--;
      for(int j=R+1;j<=r;j++) cnt[v-1][a[j]]--;
      printf("%lld
",ans);
    }
  return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/9745765.html