现在的位置: 首页 > 综合 > 正文

BZOJ 3809 Gty的二逼妹子序列 莫队算法+分块

2017年11月21日 ⁄ 综合 ⁄ 共 1860字 ⁄ 字号 评论关闭

题目大意:给出一个数列,问[x,y]中间有多少种不同的数字在[a,b]之间。

思路:又是傻逼莫队……

如果没有[a,b]的限制,那么就是傻逼莫队

这个限制就比较坑爹了,当然常规一点的想法还是树套树,很明显这个空间限制是卡树套树的。

所以就只能莫队了。然而暴力的求[a,b]之间有多少个数的话时间就到了O(n^2),但是利用一下分块,时间复杂度就是O(n*sqrt(n))了。

CODE:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define SIZE 350
#define MAX 100010
using namespace std;
 
namespace IStream{
    const int L=1<<15;
    char buffer[L],*S,*T;
    inline char Get_Char()
    {
        if(S==T)
        {
            T=(S=buffer)+fread(buffer,1,L,stdin);
            if(S==T) return EOF;
        }
        return *S++;
    }
    inline int GetInt()
    {
        char c;
        int re=0;
        for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
        while(c>='0'&&c<='9')
            re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();
        return re;
    }
}
 
int size;
int cnt,asks;
 
int src[MAX],belong[MAX];
int begin[SIZE];
 
struct Ask{
    int x,y,a,b;
    int id;
     
    bool operator <(const Ask &a)const {
        if(belong[x] == belong[a.x])    return y < a.y;
        return x < a.x;
    }
    void Read(int p) {
        x = IStream::GetInt();
        y = IStream::GetInt();
        a = IStream::GetInt();
        b = IStream::GetInt();
        id = p;
    }
}ask[1000010];
int colors[MAX],num[SIZE];
 
int ans[1000010];
 
inline void Add(int col)
{
    if(!colors[col])
        ++num[belong[col]];
    ++colors[col];
}
 
inline void Del(int col)
{
    if(colors[col] == 1)
        --num[belong[col]];
    --colors[col];
}
 
inline int Query(int a,int b)
{
    int re = 0;
    if(belong[a] == belong[b]) {
        for(int i = a; i <= b; ++i)
            re += colors[i] ? 1:0;
        return re;
    }
    int l = belong[a] + 1,r = belong[b] - 1;
    for(int i = l; i <= r; ++i)  re += num[i];
    for(int i = a; belong[i] == belong[a]; ++i)
        re += colors[i] ? 1:0;
    for(int i = begin[belong[b]]; i <= b; ++i)
        re += colors[i] ? 1:0;
    return re;
}
 
int main()
{
    cin >> cnt >> asks;
    size = sqrt(cnt);
    for(int i = 1; i <= cnt; ++i) {
        belong[i] = i / size;
        if(!begin[belong[i]])
            begin[belong[i]] = i;
    }
    for(int i = 1; i <= cnt; ++i)
        src[i] = IStream::GetInt();
    for(int i = 1; i <= asks; ++i)
        ask[i].Read(i);
    sort(ask + 1,ask + asks + 1);
    int l = 1,r = 0;
    for(int i = 1; i <= asks; ++i) {
        while(r < ask[i].y)  Add(src[++r]);
        while(l > ask[i].x)  Add(src[--l]);
        while(r > ask[i].y)  Del(src[r--]);
        while(l < ask[i].x)  Del(src[l++]);
        ans[ask[i].id] = Query(ask[i].a,ask[i].b);
    }
    for(int i = 1; i <= asks; ++i)   
        printf("%d\n",ans[i]);
    return 0;
}

抱歉!评论已关闭.