似乎莫对算法才是正确的的姿势
不过直接分块暴力也可以
需要与处理几个东西和作诗那个题非常的相似,只不过那个题是强制在线的
维护到从开始每一个块的颜色的前缀和,块到块之间的答案
询问的时候,不跨过块就排序暴力判断,跨过块就先统计整块的答案,然后把两边的的单独排序暴力更新答案
学了莫队之后似乎就要换个姿势了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int sc()
{
int i=0;char c=getchar();
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
return i;
}
int block_ans[233][233],block_sum[233][50005],bl[50005];
int a[50005],tim[50005],f[50005],st[5005];
long long C[50005];
int n,m,block,TI,col;
long long gcd(ll x,ll y){return x==0?y:gcd(y%x,x);}
void print(long long x,long long y)
{
if(x==0||y==0)puts("0/1");
else
{
long long c=gcd(x,y);
printf("%lld/%lld\n",x/c,y/c);
}
}
int main()
{
n=sc();m=sc();block=sqrt(n);
for(int i=1;i<=n;i++)
{
a[i]=sc();
bl[i]=(i-1)/block+1;
C[i]=(ll)i*(i-1)/2;
col=max(col,a[i]);
}
for(int i=1;i*block+1<=n;i++)
{
TI++;
for(int j=i*block+1;j<=n;j++)
{
int x=a[j];
if(tim[x]!=TI)tim[x]=TI,f[x]=0;
f[x]++;
block_ans[i][bl[j]]+=C[f[x]]-C[f[x]-1];
if(j%block==0)
{
block_ans[i][bl[j]]+=block_ans[i][bl[j]-1];
}
}
}
for(int i=1;i<=n;i++)
block_sum[bl[i]][a[i]]++;
for(int i=2;i*block+1<=n;i++)
for(int j=0;j<=col;j++)
block_sum[i][j]+=block_sum[i-1][j];
for(int i=1;i<=m;i++)
{
int l=sc(),r=sc();
if(bl[l]==bl[r])
{
int top=0,cnt=0;
for(int j=l;j<=r;j++)st[++top]=a[j];
sort(st+1,st+top+1);
long long ans=0;
for(int j=1;j<=top;j++)
{
cnt++;
if(st[j]!=st[j+1]||j==top)
ans+=C[cnt],cnt=0;
}
print(ans,C[r-l+1]);
}
else
{
int top=0,cnt=0,x=bl[l],y=bl[r];
long long ans=block_ans[x][y-1];
for(int j=l;bl[j]==x;j++)st[++top]=a[j];
for(int j=r;bl[j]==y;j--)st[++top]=a[j];
sort(st+1,st+top+1);
for(int j=1;j<=top;j++)
{
cnt++;
if(st[j]!=st[j+1]||j==top)
{
int u=st[j];
int temp=block_sum[y-1][u]-block_sum[x][u];
ans+=C[cnt+temp]-C[temp];
cnt=0;
}
}
print(ans,C[r-l+1]);
}
}
return 0;
}
补上莫队算法
为什么这么快–?
和普通分块相差整整5s 时间只是普通分块的一个零头
果然是黑科技啊,代码简单,越看越像暴力,然而复杂度就是n*sqrt(n)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int sc()
{
int i=0;char c=getchar();
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
return i;
}
struct W{int l,r,pos;}q[50005];
struct E{long long x,y;}ans[50005];
int a[50005],sum[50005],bl[50005];
int n,m,now=0,l,r,block;
bool cmp(W a,W b){return bl[a.l]==bl[b.l]?a.r<b.r:bl[a.l]<bl[b.l];}
long long gcd(ll x,ll y){return x==0?y:gcd(y%x,x);}
void print(long long x,long long y)
{
if(x==0||y==0)puts("0/1");
else
{
long long c=gcd(x,y);
printf("%lld/%lld\n",x/c,y/c);
}
}
int main()
{
n=sc();m=sc();block=sqrt(n);
for(int i=1;i<=n;i++)
{
a[i]=sc();
bl[i]=(i-1)/block+1;
}
for(int i=1;i<=m;i++)q[i]=(W){sc(),sc(),i};
sort(q+1,q+m+1,cmp);
l=r=q[1].l;
sum[a[q[1].l]]=1;
for(int i=1;i<=m;i++)
{
while(l<q[i].l)now-=(--sum[a[l++]]);
while(r>q[i].r)now-=(--sum[a[r--]]);
while(l>q[i].l)now+=(sum[a[--l]]++);
while(r<q[i].r)now+=(sum[a[++r]]++);
ans[q[i].pos]=(E){now,(ll)(r-l+1)*(r-l)/2};
}
for(int i=1;i<=m;i++)print(ans[i].x,ans[i].y);
return 0;
}