您的位置:首页 > 其它

BZOJ 5016: [Snoi2017]一个简单的询问 莫队算法

2018-02-26 19:14 330 查看

5016: [Snoi2017]一个简单的询问

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 193  Solved: 147
[Submit][Status][Discuss]

Description

给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出

get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次。

Input

第一行,一个数字N,表示序列长度。第二行,N个数字,表示a1~aN第三行,一个数字Q,表示询问个数。第4~Q+3行,每行四个数字l1,r1,l2,r2,表示询问。N,Q≤50000N1≤ai≤N1≤l1≤r1≤N1≤l2≤r2≤N注意:答案有可能超过int的最大值

Output

对于每组询问,输出一行一个数字,表示答案

Sample Input

5
1 1 1 1 1
2
1 2 3 4
1 1 4 4

Sample Output

4
1

看了两个乘到一起觉得莫队不行 就狂想数据结构 最后没做出来
这个应该是一种降低运算级从而简化运算的思想
具体来讲
定义 s(i)=get(1,i,x) 令 l1--,l2--
则 原式= sigma (s(r1)-s(l1))*(s(r2)-s(l2))
展开之后 可以化成四个平方的和
sigma ((s(r1)−s(l2))^2+(s(r2)−s(l1))^2−(s(l2)−s(l1))^2−(s(r2)−s(r1))^2)/2

之后就可以莫队了

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

typedef double db;
typedef long long ll;

inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(ll x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=50100;

int bel
;

struct query
{
int l,r,pos,opt;

friend bool operator <(const query &x,const query &y)
{return bel[x.l]==bel[y.l] ? x.r<y.r : bel[x.l]<bel[y.l];}

}q[N<<2];

int n,Q,tot;
int a
;
ll res,ans
;

int num
;

inline void modify(int x,int opt)
{
res+=1+(opt*num[x]<<1);
num[x]+=opt;
}

void solve()
{
sort(q+1,q+1+tot);
register int i,l(1),r(0);
for(i=1;i<=tot;++i)
{
while(r<q[i].r) r++,modify(a[r],1);
while(l>q[i].l) l--,modify(a[l],1);
while(r>q[i].r) modify(a[r],-1),r--;
while(l<q[i].l) modify(a[l],-1),l++;
ans[q[i].pos]+=q[i].opt*res;
}
}

int main()
{
n=read();
register int i,j,l1(1),l2,r1,r2;
for(i=1;i<=n;++i) a[i]=read();
int block(floor(sqrt(n)));
for(i=0,j=1;i<=n;++i,++j)
{
bel[i]=l1;
if(j==block) j=0,l1++;
}
Q=read();
for(i=1;i<=Q;++i)
{
l1=read()-1;r1=read();
l2=read()-1;r2=read();
q[++tot]=(query){min(l1,r2)+1,max(l1,r2),i,1};
q[++tot]=(query){min(r1,l2)+1,max(r1,l2),i,1};
q[++tot]=(query){min(l1,l2)+1,max(l1,l2),i,-1};
q[++tot]=(query){min(r1,r2)+1,max(r1,r2),i,-1};
}
solve();
for(i=1;i<=Q;++i)
print(ans[i]>>1),putchar('\n');
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: