Luogu8078
前言
快写害死人!(场上我快写写挂,痛失 \(100pts\))
没想到回滚莫队 + 链表等神仙做法,于是憨憨地打了一个压位 Trie+ 普通莫队。
前置芝士
- 普通莫队算法
- 压位 Trie
解法
你发现暴力莫队 \(O(n\sqrt n\log n)\) 很悬。
你考虑优化它。
你发现它要支持插入、删除、前驱、后继操作,即 Dynamic Predecessor Problem。
平衡树于是可以换成压位 Trie。
然后跑得还蛮快?
复杂度 \(O(n\sqrt n\log_wn)\),(应该)可以通过。
Code
实现了一个压位 Trie。
#include <bits/stdc++.h>
using namespace std;
#define ONLINE_JUDGE
/* --------------- fast io --------------- */ // begin
namespace Fread{
const int SIZE= 1 << 16;
char buf[SIZE],*S,*T;
inline char getchar(){if(S==T){T=(S=buf)+
fread(buf,1,SIZE,stdin);if(S==T)return'\n';}return *S++;}
} // namespace Fread
namespace Fwrite {
const int SIZE= 1 << 16;
char buf[SIZE],*S=buf,*T=buf+SIZE;
inline void flush(){fwrite(buf,1,S-buf,stdout);S=buf;}
inline void putchar(char c){*S++=c;if(S==T)flush();}
struct NTR{~NTR(){flush();}}ztr;
} // namespace Fwrite
#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endif
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <vector>
typedef long long llt;
typedef unsigned uint;typedef unsigned long long ullt;
typedef bool bol;typedef char chr;typedef void voi;
typedef double dbl;
template<typename T>bol _max(T&a,T b){return(a<b)?a=b,true:false;}
template<typename T>bol _min(T&a,T b){return(b<a)?a=b,true:false;}
template<typename T>T power(T base,T index,T mod){return((index<=1)?(index?base:1):(power(base*base%mod,index>>1,mod)*power(base,index&1,mod)))%mod;}
template<typename T>T lowbit(T n){return n&-n;}
template<typename T>T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<typename T>T lcm(T a,T b){return(a!=0||b!=0)?a/gcd(a,b)*b:(T)0;}
template<typename T>T exgcd(T a,T b,T&x,T&y){if(!b)return y=0,x=1,a;T ans=exgcd(b,a%b,y,x);y-=a/b*x;return ans;}
const uint Dep=5,W=64,LogW=6,And=W-1,Val=16777216;
ullt BUFF[Val>>LogW<<1|1];
ullt*BT=BUFF+sizeof(BUFF)/sizeof(ullt);
ullt*NewMemory(uint siz){return BT-=siz;}
inline uint hp(ullt v){return W-__builtin_clzll(v)-1;}
inline uint lp(ullt v){return __builtin_ctzll(v);}
struct Trie // 压位 Trie
{
ullt*Node[Dep-1];
Trie(){for(uint i=0;i+1<Dep;i++)Node[i]=NewMemory(1llu<<(LogW*i));}
inline voi insert(uint v)
{
for(uint i=Dep-2;~i;i--)
{
if(Node[i][v>>LogW]>>(v&And)&1)return;
Node[i][v>>LogW]|=1llu<<(v&And),v>>=LogW;
}
}
inline voi erase(uint v)
{
if(!(Node[Dep-2][v>>LogW]>>(v&And)&1))return;
for(uint i=Dep-2;~i;i--)
{
Node[i][v>>LogW]&=~(1llu<<(v&And)),v>>=LogW;
if(Node[i][v])return;
}
}
inline uint pre(uint v)
{
for(uint i=Dep-2;~i;i--,v>>=LogW)
if(Node[i][v>>LogW]&~((-1llu)<<(v&And)))
{
uint p=hp(Node[i][v>>LogW]&~((-1llu)<<(v&And)))|(v>>LogW<<LogW);
while(++i<=Dep-2)p=(p<<LogW)|hp(Node[i][p]);
return p;
}
return 0;
}
inline uint suf(uint v)
{
for(uint i=Dep-2;~i;i--,v>>=LogW)
if(Node[i][v>>LogW]&((-1llu)<<(v&And)<<1))
{
uint p=lp(Node[i][v>>LogW]&((-1llu)<<(v&And)<<1))|(v>>LogW<<LogW);
while(++i<=Dep-2)p=(p<<LogW)|lp(Node[i][p]);
return p;
}
return 0;
}
}T;
struct ques{uint l,r,t;}Q[500005];
uint A[500005],Back[500005];
ullt Ans[500005];
ullt ans=0;
#define dist(a,b) Back[a]>Back[b]?Back[a]-Back[b]:Back[b]-Back[a]
inline voi insert(uint v)
{
uint p=T.pre(v),s=T.suf(v);
T.insert(v);
if(p)ans+=dist(p,v);
if(s)ans+=dist(v,s);
if(p&&s)ans-=dist(p,s);
}
inline voi erase(uint v)
{
T.erase(v);
uint p=T.pre(v),s=T.suf(v);
if(p)ans-=dist(p,v);
if(s)ans-=dist(v,s);
if(p&&s)ans+=dist(p,s);
}
inline uint read()
{
uint ans=0;chr c;do c=getchar();while(c>'9'||c<'0');
do ans=ans*10+(c^'0'),c=getchar();while(c<='9'&&c>='0');return ans;
}
inline voi write(ullt v)
{
static chr c[18];uint cnt=0;do c[cnt++]=v%10+'0',v/=10;while(v);
while(cnt--)putchar(c[cnt]);
putchar('\n');
}
int main()
{
// freopen("rrad_s_500000.in","r",stdin);
// freopen("rrads.out","w",stdout);
uint n,m;n=read(),m=read();
uint Siz=n/(sqrt(m)+1.2)*sqrt(1.5)+5;
// 莫队 O(n\sqrt m\log_w n)
for(uint i=0;i<n;i++)Back[A[i]=read()]=i;
for(uint i=0;i<m;i++)Q[i].l=read()-1,Q[i].r=read(),Q[i].t=i;
std::sort(Q,Q+m,[Siz](const ques&a,const ques&b){return a.l/Siz==b.l/Siz?((a.l/Siz)&1)?a.r>b.r:a.r<b.r:a.l<b.l;});
uint l=0,r=0;
for(uint i=0;i<m;i++)
{
ques&qs=Q[i];
while(l>qs.l)insert(A[--l]);
while(r<qs.r)insert(A[r++]);
while(r>qs.r)erase(A[--r]);
while(l<qs.l)erase(A[l++]);
Ans[qs.t]=ans;
}
for(uint i=0;i<m;i++)write(Ans[i]);
return 0;
}
本文来自博客园,作者:myee,转载请注明原文链接:https://www.cnblogs.com/myee/p/Luogu-solution-p8078.html