莫队算法--小Z的袜子

啊概率什么的化简什么的我就不管了

反正化出来公式就是要求求区间内各个颜色的个数的平方和

坑点就是要分清楚是先加减在传值还是先传值后加减

噢对了今天就像失恋了一样

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 50001
int n,m,s[maxn],basket[maxn],visit[maxn],answer[maxn];
long long ans=0;
struct note
{
int l,r,num;
}ask[maxn];
void clear()
{
memset(s,0,sizeof(int));
memset(basket,0,sizeof(int));
memset(visit,0,sizeof(int));
}
int cmp(struct note a,struct note b)
{
if(a.l<b.l||a.l==b.l&&a.r<b.r) return 1;
return 0;
}
int query(int left,int right)
{
int c=0,max=-999999,min=999999;
for(int i=left;i<=right;i++) basket[s[i]]++;
for(int i=left;i<=right;i++)
if(visit[s[i]]==0) c=c+basket[s[i]]*basket[s[i]],visit[s[i]]=1;
return c;
}
void move(int flag,int pos)//flag表示添加进来的还是删掉的,pos是位数
{
int temp=basket[s[pos]]*basket[s[pos]];
ans-=temp;
if(!flag)  basket[s[pos]]--;
else basket[s[pos]]++;
ans+=basket[s[pos]]*basket[s[pos]];
}
int main()
{
    clear();
int temp1,temp2;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&s[i]);
for(int i=1;i<=m;i++)
{scanf("%d%d",&ask[i].l,&ask[i].r);ask[i].num=i;}
sort(ask+1,ask+1+m,cmp);
int left=ask[1].l,right=ask[1].r;
answer[ask[1].num]=query(ask[1].l,ask[1].r);
ans+=answer[ask[1].num];
for(int i=2;i<=m;i++)
{
while(left<ask[i].l) move(0,left++);
while(right<ask[i].r)move(1,++right);
while(right>ask[i].r)move(0,right--);
answer[ask[i].num]=ans;
}
for(int i=1;i<=m;i++)  printf("%d\n",answer[i]);
}

 

posted @ 2017-04-10 22:01  OcahIBye  阅读(156)  评论(0编辑  收藏  举报