参考博客:莫队算法——解决序列上询问的利器
题目:P2709 小B的询问
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 50005;
int a[maxn];
struct Node{
int l, r, i;
}pos[maxn];
int ans = 0, block;
int cnt[maxn], res[maxn];
void Add(int x){//先减去之前的,更新一下,加上现在的
ans -= cnt[a[x]]*cnt[a[x]];
++cnt[a[x]];
ans += cnt[a[x]] * cnt[a[x]];
}
void Remove(int x){
ans -= cnt[a[x]]*cnt[a[x]];
--cnt[a[x]];
ans += cnt[a[x]] * cnt[a[x]];
}
inline int read(){
int k=0;
char c;
c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c)){k=(k<<3)+(k<<1)+c-'0';c=getchar();}
return k;
}
bool cmp(Node A, Node B){
if(A.l / block == B.l/ block)return A.r < B.r;
else return A.l < B.l;
}
int main(){
int n, m, k;
n = read();
m = read();
k = read();
for(int i = 1; i <= n; i++){
a[i] = read();
}
block = sqrt(n);
for(int i = 1; i <= m; i++){
pos[i].l = read();
pos[i].r = read();
pos[i].i = i;
}
sort(pos+1, pos+m+1, cmp);
int L = 1, R = 0;
ans = 0;
for(int i = 1; i <= m; i++){
while(L < pos[i].l){
Remove(L++);
}
while(L > pos[i].l){
Add(--L);
}
while(R < pos[i].r){
Add(++R);
}
while(R > pos[i].r){
Remove(R--);
}
// cout<<ans<<endl;
res[pos[i].i] = ans;
}
for(int i = 1; i <= m; i++){
printf("%d\n", res[i]);
}
return 0;
}
题目:2038: [2009国家集训队]小Z的袜子(hose)
注意:这道题所有的数据都要开long long,不要问我为什么,我也不知道,因为这个卡了一个多点
下面的两组代码在更新的时候稍微有点差别,其他的都一样。
代码1:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 50005;
LL a[maxn];
struct Node
{
LL l, r, i;
} pos[maxn];
LL gcd(LL a, LL b)
{
if(!b)return a;
else return gcd(b, a % b);
}
LL ans = 0;
LL block;
LL cnt[maxn], sum[maxn], res[maxn];
void Add(int x)
{
++cnt[a[x]];
if(cnt[a[x]] > 1)
ans += (cnt[a[x]]-1);
}
void Remove(int x)
{
--cnt[a[x]];
if(cnt[a[x]] > 0)ans -= cnt[a[x]];
}
bool cmp(Node A, Node B)
{
if(A.l / block == B.l/ block)return A.r < B.r;
else return A.l < B.l;
}
int main()
{
LL n, m;
scanf("%lld %lld", &n, &m);
memset(cnt, 0, sizeof(cnt));
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
}
block = sqrt(n);
for(int i = 1; i <= m; i++)
{
scanf("%lld %lld", &pos[i].l, &pos[i].r);
pos[i].i = i;
}
sort(pos+1, pos+m+1, cmp);
LL L = 1, R = 0;
ans = 0;
for(int i = 1; i <= m; i++)
{
while(L < pos[i].l)
{
Remove(L++);
}
while(L > pos[i].l)
{
Add(--L);
}
while(R < pos[i].r)
{
Add(++R);
}
while(R > pos[i].r)
{
Remove(R--);
}
if(ans == 0)
{
res[pos[i].i] = 0;
sum[pos[i].i] = 1;
}
LL result = (pos[i].r-pos[i].l+1)*(pos[i].r-pos[i].l)/2;
LL t = gcd(result, ans);
res[pos[i].i] = ans/t;
sum[pos[i].i] = result/t;
}
for(int i = 1; i <= m; i++)
{
printf("%lld/%lld\n", res[i],sum[i]);
}
return 0;
}
代码2:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 50005;
LL a[maxn];
struct Node
{
LL l, r, p;
} pos[maxn];
LL gcd(LL a, LL b)
{
if(!b)return a;
else return gcd(b, a % b);
}
LL ans = 0;
LL block;
LL cnt[maxn], sum[maxn], res[maxn];
void Add(int x)
{
ans -= cnt[a[x]]*(cnt[a[x]] - 1) / 2;
++cnt[a[x]];
ans += cnt[a[x]]*(cnt[a[x]] - 1) / 2;
}
void Remove(int x)
{
ans -= cnt[a[x]]*(cnt[a[x]] - 1) / 2;
--cnt[a[x]];
ans += cnt[a[x]]*(cnt[a[x]] - 1) / 2;
}
bool cmp(Node A, Node B)
{
if(A.l / block == B.l/ block)return A.r < B.r;
else return A.l < B.l;
}
int main()
{
LL n, m;
scanf("%lld %lld", &n, &m);
memset(cnt, 0, sizeof(cnt));
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
}
block = sqrt(n);
for(int i = 1; i <= m; i++)
{
scanf("%lld %lld", &pos[i].l, &pos[i].r);
pos[i].p = i;
}
sort(pos+1, pos+m+1, cmp);
LL L = 1, R = 0;
ans = 0;
for(int i = 1; i <= m; i++)
{
while(L < pos[i].l)
{
Remove(L++);
}
while(L > pos[i].l)
{
Add(--L);
}
while(R < pos[i].r)
{
Add(++R);
}
while(R > pos[i].r)
{
Remove(R--);
}
if(ans == 0)
{
res[pos[i].p] = 0;
sum[pos[i].p] = 1;
}
LL result = (pos[i].r-pos[i].l+1)*(pos[i].r-pos[i].l)/2;
LL t = gcd(result, ans);
res[pos[i].p] = ans/t;
sum[pos[i].p] = result/t;
}
for(int i = 1; i <= m; i++)
{
printf("%lld/%lld\n", res[i],sum[i]);
}
return 0;
}