LOJ.6282.数列分块入门6(块状链表/分块)

Posted SovietPower

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LOJ.6282.数列分块入门6(块状链表/分块)相关的知识,希望对你有一定的参考价值。

题目链接
1.分块(vector)+重构

//直接上vector(本机还是比较慢的...) 某块size较大时O(n)重构 
//注意细节 
#include <cmath>
#include <cstdio>
#include <cctype>
#include <vector>
#define gc() getchar()
#define pb push_back
typedef long long LL;
const int N=1e5+5;

int n,size,tmp[N<<1],bel;
std::vector<int> v[500];
std::vector<int>::iterator it;

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
inline int Get_Pos(int &p)
{
    for(int i=1; i<=bel; ++i)
        if((p-=v[i].size())<=0) {p+=v[i].size(); return i;}
}
void Rebuild()
{
    int tot=0;
    for(int i=1; i<=bel; ++i)
    {
        for(it=v[i].begin(); it!=v[i].end(); ++it) tmp[++tot]=*it;
        v[i].clear();
    }
    size=sqrt(tot);
    for(int i=1; i<=tot; ++i) bel=(i-1)/size+1, v[bel].pb(tmp[i]);
}
void Insert(int p,int val)
{
    int id=Get_Pos(p);
    v[id].insert(v[id].begin()+p-1,val);
    if(v[id].size()>size*15) Rebuild();
}

int main()
{
    n=read(), size=sqrt(n);
    for(int i=1; i<=n; ++i) bel=(i-1)/size+1,v[bel].pb(read());
    for(int opt,l,r,c,id,i=1; i<=n; ++i)
    {
        opt=read(),l=read(),r=read(),c=read();
        if(opt) id=Get_Pos(r),printf("%d\n",v[id][r-1]);
        else Insert(l,r);
    }
    return 0;
}

2.块状链表

#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=1e5+5;

int n,size,H[N],nxt[N],nxtv[N<<1],A[N<<1],sz[N];//二倍数组!mdzzC++数组越界各种奇葩错误(这指针无语) 

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
inline int New_Node()
{
    static int cnt=n;
    return ++cnt;
}
inline int New_Block()
{
    static int cnt=(n-1)/size+1;
    return ++cnt;
}
void Init()
{
    for(int i=1; i<=n; ++i) A[i]=read();
    int tot=(n-1)/size+1;
    H[0]=1;
    for(int now=0,i=1; i<tot; ++i)//块整体的链表 
        H[i]=(i-1)*size+1, nxt[i]=i+1, sz[i]=size;
    sz[tot]=n-(tot-1)*size, H[tot]=(tot-1)*size+1;
    for(int i=1,tmp=i*size; i<=tot; tmp=++i*size)//块内链表 
        for(int j=(i-1)*size+1; j<tmp; ++j)
            nxtv[j]=j+1;
}
int Get_Pos(int &p)
{
    for(int i=H[0]; i; i=nxt[i])
        if((p-=sz[i])<=0) {p+=sz[i]; return i;}
}
int Query(int p)
{
    int id=Get_Pos(p);
    for(int i=H[id]; i; i=nxtv[i])
        if(!--p) return A[i];
}
void Insert(int p,int v)
{
    int id=Get_Pos(p),pos=New_Node();
    A[pos]=v, ++sz[id];
//  printf("I pos:%d id:%d p:%d size:%d stdsz:%d sz[id]:%d\n",pos,id,p,size*(id-1)+p,size,sz[id]);
    if(!p) nxtv[pos]=H[id], H[id]=pos;
    else
        for(int i=H[id]; i; i=nxtv[i])
            if(!--p) {nxtv[pos]=nxtv[i], nxtv[i]=pos; break;}
    if(sz[id] > size<<1)//2倍比较合适 
    {
        p=size;
        for(int i=H[id]; i; i=nxtv[i])
            if(!(--p)) {pos=nxtv[i], nxtv[i]=0; break;}
        int posb=New_Block();
        H[posb]=pos, nxt[posb]=nxt[id], nxt[id]=posb, sz[posb]=sz[id]-size, sz[id]=size;
    }
}
//void Print()
//{
//  puts("Output:");
//  for(int i=H[0]; i; i=nxt[i])
//      for(int j=H[i]; j; j=nxtv[j])
//          printf("%d ",A[j]);
//  putchar('\n');
//}

int main()
{
    n=read(), size=sqrt(n);
    Init();
    for(int opt,l,r,c,i=1; i<=n; ++i)
    {
        opt=read(),l=read(),r=read(),c=read();
        if(opt) printf("%d\n",Query(r));
        else Insert(l-1,r);
    }
    return 0;
}

以上是关于LOJ.6282.数列分块入门6(块状链表/分块)的主要内容,如果未能解决你的问题,请参考以下文章

LOJ#6282. 数列分块入门 6

Loj 6282. 数列分块入门 6

LibreOJ 6282. 数列分块入门 6

数列分块入门6 解题报告

分块,莫队,BSGS,块状链表

数列分块入门7 解题报告