根号数据结构

莫队算法练习题

前导知识

普通莫队带修改莫队树上莫队回滚莫队莫队配合bitset

1. 数列找不同

传送门

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n,q;
int a[N],vis[N],s[N],now,ans[N];
int l,r;
struct node{
    int l,r,id;
    bool operator <(const node b) const{
        return s[l]==s[b.l]?r<b.r:s[l]<s[b.l];
    }
}Q[N];
inline int read(){
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-f;ch=getchar();}
    while (ch<='9'&&ch>='0') ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
inline void del(int x){vis[a[x]]--;if (!vis[a[x]]) now--;}
inline void add(int x){vis[a[x]]++;if (vis[a[x]]==1) now++;}
int main(){
    n=read();q=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    for(int i=1;i<=q;i++){
        Q[i].l=read();Q[i].r=read();Q[i].id=i;
    }
    int si=sqrt(n);
    int num=ceil((double)n/si);
    for(int i=1;i<=num;i++)
        for(int j=(i-1)*si+1;j<=i*si;j++)
            s[j]=i;
    sort(Q+1,Q+q+1);
    for(int i=1;i<=q;i++){
        while(l<Q[i].l) del(l++);
        while(l>Q[i].l) add(--l);
        while(r<Q[i].r) add(++r);
        while(r>Q[i].r) del(r--);
        if(now==Q[i].r-Q[i].l+1) ans[Q[i].id]=1;
    }
    for(int i=1;i<=q;i++){
        if(!ans[i]) printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}

2. 小z的袜子

传送门

#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
const int N = 50005;
int n, m, maxn;
int c[N];
long long sum;
int cnt[N];
long long ans1[N], ans2[N];
struct query{
    int l, r, id;
    bool operator<(const query &x) const {
        if (l / maxn != x.l / maxn) return l < x.l;
        return (l / maxn) & 1 ? r < x.r : r > x.r;
    }
}a[N];
void add(int i) {
    sum += cnt[i];
    cnt[i]++;
}
void del(int i) {
    cnt[i]--;
    sum -= cnt[i];
}
long long gcd(long long a, long long b) {
    return b ? gcd(b, a % b) : a;
}
int main() {
    scanf("%d%d", &n, &m);
    maxn = sqrt(n);
    for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
    for (int i = 0; i < m; i++) scanf("%d %d", &a[i].l, &a[i].r), a[i].id = i;
    sort(a, a + m);
    for (int i = 0, l = 1, r = 0; i < m; i++) {
        if (a[i].l == a[i].r) {
            ans1[a[i].id] = 0, ans2[a[i].id] = 1;
            continue;
        }
        while (l > a[i].l) add(c[--l]);
        while (r < a[i].r) add(c[++r]);
        while (l < a[i].l) del(c[l++]);
        while (r > a[i].r) del(c[r--]);
        ans1[a[i].id] = sum;
        ans2[a[i].id] = (long long)(r - l + 1) * (r - l) / 2;
    }
    for (int i = 0; i < m; i++) {
        if (ans1[i] != 0) {
            long long g = gcd(ans1[i], ans2[i]);
            ans1[i] /= g, ans2[i] /= g;
        } else
            ans2[i] = 1;
        printf("%lld/%lld\n", ans1[i], ans2[i]);
    }
    return 0;
}

3. 异或序列

传送门

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeeGLMath

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值