常用黑盒
扫描线维护区间 mex
#define pii pair<int,int>
#define mpr make_pair
#define fir first
#define sec second
const int N=;
struct Segment_Tree1{
#define ls (rt<<1)
#define rs (rt<<1|1)
int mn[N<<2];
inline void pushup(int rt){
mn[rt]=min(mn[ls],mn[rs]);
}
inline void build(int rt,int l,int r){
mn[rt]=0;
if(l==r) return ;
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
inline void modify(int rt,int l,int r,int p,int v){
if(l==r){
mn[rt]=v;
return ;
}
int mid=l+r>>1;
if(p<=mid) modify(ls,l,mid,p,v);
else modify(rs,mid+1,r,p,v);
pushup(rt);
}
inline pii query(int rt,int l,int r,int v){
if(mn[rt]>v) return mpr(-1,-1);
if(l==r) return mpr(l,mn[rt]);
int mid=l+r>>1;
pii tmp=query(ls,l,mid,v);
if(tmp.fir!=-1) return tmp;
return query(rs,mid+1,r,v);
}
}T1;
struct Segment_Tree2{
#define ls (rt<<1)
#define rs (rt<<1|1)
int mx[N<<2],tag[N<<2];
inline void pushup(int rt){
mx[rt]=max(mx[ls],mx[rs]);
}
inline void pushtag(int rt,int v){
mx[rt]=tag[rt]=v;
}
inline void pushdown(int rt){
if(tag[rt]==-1) return ;
pushtag(ls,tag[rt]);
pushtag(rs,tag[rt]);
tag[rt]=-1;
}
inline void build(int rt,int l,int r){
mx[rt]=0,tag[rt]=-1;
if(l==r) return ;
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
inline void modify(int rt,int l,int r,int L,int R,int v){
if(L<=l&&r<=R){
pushtag(rt,v);
return ;
}
pushdown(rt);
int mid=l+r>>1;
if(L<=mid) modify(ls,l,mid,L,R,v);
if(R>mid) modify(rs,mid+1,r,L,R,v);
pushup(rt);
}
inline int query(int rt,int l,int r,int v){
if(mx[rt]<v) return -1;
if(l==r) return l;
pushdown(rt);
int mid=l+r>>1;
int tmp=query(rs,mid+1,r,v);
if(tmp==-1) tmp=query(ls,l,mid,v);
pushup(rt);
return tmp;
}
#undef ls
#undef rs
}T2;
struct node{
mutable int l,r,v;
node(int V=0){ l=r=n+1,v=V; }
node(int L,int R,int V){ l=L,r=R,v=V; }
inline friend bool operator<(const node &a,const node &b){
return a.v<b.v||(a.v==b.v&&a.l>b.l);
}
};
set<node>st;
int main(){
/*
...
*/
for(int i=1;i<=n;i++){
int x=b[i];
st.insert(node(i,i,0));
T1.modify(1,0,n+1,x,i);
T2.modify(1,1,n,i,i,0);
auto it=st.lower_bound(node(x));
for(;it!=st.end()&&(it->v==x);){
int l=(*it).l,r=(*it).r;
auto itr=it;
for(++itr;itr!=st.end();++itr)
if(itr->v==x&&itr->r==l-1) l=itr->l;
else break;
st.erase(it,itr);
while(r>=l){
pii tmp=T1.query(1,0,n+1,r-1);
int y=tmp.fir,L=max(l,tmp.sec+1);
st.insert(node(L,r,y));
T2.modify(1,1,n,L,r,y);
r=L-1;
}
it=st.lower_bound(node(x));
}
}
/*
...
*/
}
时间复杂度 \(O(n\log n)\)。
FHQ-Treap 维护凸分段一次函数
const int N=;
const ll INF=1e16;
namespace FHQ_Func{
//下凸壳
//(len,v) 长为 len,斜率为 v
mt19937_64 R(time(0));
struct node{
ll len,siz,v,tag;
int pr,cnt,son[2];
}a[N*10];
#define ls (a[rt].son[0])
#define rs (a[rt].son[1])
int stk[N*10],top,siz;
namespace Opers{
inline void del(int rt){
stk[++top]=rt;
}
inline int newnode(ll len,ll v){
if(!len) return 0;
int rt=top?stk[top--]:++siz;
ls=rs=0,a[rt].pr=R(),a[rt].len=a[rt].siz=len;
a[rt].v=v,a[rt].tag=0,a[rt].cnt=1;
return rt;
}
inline void pushup(int rt){
a[rt].siz=a[ls].siz+a[rs].siz+a[rt].len;
a[rt].cnt=a[ls].cnt+a[rs].cnt+1;
}
inline void pushtag(int rt,ll v){
if(!rt) return ;
a[rt].v+=v,a[rt].tag+=v;
}
inline void pushdown(int rt){
if(!a[rt].tag) return ;
if(ls) pushtag(ls,a[rt].tag);
if(rs) pushtag(rs,a[rt].tag);
a[rt].tag=0;
}
inline void split0(int rt,int &x,int &y,ll k){
if(!rt){
x=y=0;
return ;
}
pushdown(rt);
if(a[ls].siz+a[rt].len<=k)
x=rt,split0(rs,rs,y,k-a[ls].siz-a[rt].len);
else
y=rt,split0(ls,x,ls,k);
pushup(rt);
}
inline int merge1(int x,int y){//min +
if(!x||!y) return x+y;
pushdown(x),pushdown(y);
if(a[x].pr<a[y].pr){
a[x].son[1]=merge1(a[x].son[1],y);
pushup(x);
return x;
}else{
a[y].son[0]=merge1(x,a[y].son[0]);
pushup(y);
return y;
}
}
inline int cut(int rt,ll k){
if(ls){
pushdown(rt);
int tmp=cut(ls,k);
pushup(rt);
return tmp;
}
a[rt].len-=k,a[rt].siz-=k;
return newnode(k,a[rt].v);
}
inline void split1(int rt,int &x,int &y,ll k){//[0,k]
if(!k){
x=0,y=rt;
return ;
}
if(k>=a[rt].siz){
x=rt,y=0;
return ;
}
split0(rt,x,y,k);
if(k>a[x].siz) x=merge1(x,cut(y,k-a[x].siz));
}
inline void split2(int rt,int &x,int &y,ll v){//<=v
if(!rt){
x=y=0;
return ;
}
pushdown(rt);
if(a[rt].v<=v)
x=rt,split2(rs,rs,y,v);
else
y=rt,split2(ls,x,ls,v);
pushup(rt);
}
inline int merge1s(int x,int y){//min +(值域相交)
if(!x||!y) return x+y;
if(a[x].cnt>a[y].cnt) swap(x,y);
pushdown(x);
int A,B,C,lp=a[x].son[0],rp=a[x].son[1];
split2(y,A,B,a[x].v-1);
split2(B,B,C,a[x].v);
if(B) a[B].len+=a[x].len,a[B].siz+=a[x].len;
else B=newnode(a[x].len,a[x].v);
del(x);
return merge1(merge1(merge1s(lp,A),B),merge1s(rp,C));
}
inline int merge2(int x,int y){//+
if(!x||!y) return x+y;
if(a[x].cnt>a[y].cnt) swap(x,y);
pushdown(x);
int A,B,C,lp=a[x].son[0],rp=a[x].son[1];
split1(y,A,B,a[lp].siz);
split1(B,B,C,a[x].len);
pushtag(B,a[x].v);
del(x);
return merge1(merge1(merge2(lp,A),B),merge2(rp,C));
}
inline void insert(int &rt,ll len,ll v){
int A,B,C;
split2(rt,A,B,v-1);
split2(B,B,C,v);
if(B) a[B].len+=len,a[B].siz+=len;
else B=newnode(len,v);
rt=merge1(merge1(A,B),C);
}
inline ll query(int rt){
if(!rt) return 0;
pushdown(rt);
return a[rt].v*a[rt].len+query(ls)+query(rs);
}
inline void dfs1(int rt){
if(!rt) return ;
pushdown(rt);
dfs1(ls);
printf("(%lld,%lld) %d\n",a[rt].v,a[rt].len,a[rt].siz);
dfs1(rs);
}
}
#undef ls
#undef rs
}
using namespace FHQ_Func::Opers;
维护差分序列,设定义域为 \([l,r]\)。
split1 将分裂出 \([l,l+k]\),split2 将把差分序列中 \(\le v\) 的前缀分裂出。merge1 将对两个值域不交的凸分段函数做 \((\min,+)\) 卷积,即归并差分序列,merge1s 将对两个值域相交的凸分段函数做 \((\min,+)\) 卷积,merge2 将对两个定义域相同的凸分段函数做加法。
如要求值,需要手动维护定义域左端点处值。
时间复杂度未知,不超过 \(O(n\log^2 n)\),常数较小。
KTT 维护直线
#define pfl pair<Func,ll>
#define mpr make_pair
#define fir first
#define sec second
const int N=;
const ll INF=1e18;
struct Func{
int k;
ll b;
inline friend Func operator+(const Func &a,const Func &b){
return (Func){a.k+b.k,a.b+b.b};
}
inline void add(ll v){ b+=k*v; }
};
inline pfl max(Func a,Func b){
if(a.k<b.k||a.k==b.k&&a.b<b.b) swap(a,b);
if(a.b>=b.b) return mpr(a,INF);
return mpr(b,(b.b-a.b)/(a.k-b.k));
}
struct node{
Func mx;
ll x;
inline friend node operator+(const node &a,const node &b){
node t;
pfl tmp;
t.x=min(a.x,b.x);
tmp=max(a.mx,b.mx);
t.mx=tmp.fir,t.x=min(t.x,tmp.sec);
return t;
}
};
struct KTT{
#define ls (rt<<1)
#define rs (rt<<1|1)
node a[N<<2];
ll tag[N<<2];
inline void pushup(int rt){
a[rt]=a[ls]+a[rs];
}
inline void push(int rt,ll v){
tag[rt]+=v;
a[rt].x-=v;
a[rt].mx.add(v);
}
inline void pushdown(int rt){
if(tag[rt]){
ll bas=tag[rt];
tag[rt]=0;
push(ls,bas);
push(rs,bas);
}
}
inline void build(int rt,int l,int r){
a[rt]={{0,0},INF},tag[rt]=0;
if(l==r) return ;
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
inline void modify(int rt,int l,int r,int p,int k,ll b){
if(l==r){
Func q={k,b};
a[rt]=(node){q,INF};
return ;
}
int mid=l+r>>1;
if(p<=mid) modify(ls,l,mid,p,k,b);
else modify(rs,mid+1,r,p,k,b);
pushup(rt);
}
inline void defeat(int rt,int l,int r,ll v){
if(v>a[rt].x){
int mid=l+r>>1;
ll t=tag[rt]+v;
tag[rt]=0;
defeat(ls,l,mid,t);
defeat(rs,mid+1,r,t);
pushup(rt);
}else{
push(rt,v);
}
}
inline void update(int rt,int l,int r,int L,int R,int k){
if(L<=l&&r<=R){
defeat(rt,l,r,k);
return ;
}
pushdown(rt);
int mid=l+r>>1;
if(L<=mid) update(ls,l,mid,L,R,k);
if(R>mid) update(rs,mid+1,r,L,R,k);
pushup(rt);
}
inline node query(int rt,int l,int r,int L,int R){
if(L>R) return {{0,0},INF};
if(L<=l&&r<=R)
return a[rt];
pushdown(rt);
int mid=l+r>>1;
if(R<=mid) return query(ls,l,mid,L,R);
if(L>mid) return query(rs,mid+1,r,L,R);
return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R);
}
}T;
有 \(n\) 条直线 \(f_i(x)=k_ix+b_i\),有序列 \(x_{1\sim n}\)。
update 令 \(\forall i\in[l,r],x_i\gets x_i+k(k>0)\),query 求 \(\max_{i=l}^r f_i(x_i)\)。
支持单点修改直线。
时间复杂度 \(O(n\log^2n+m\log^3 n+q\log n)\)。
区间加区间历史和
const int N=;
struct Line{
ll k,b;
Line(ll K=0,ll B=0){ k=K,b=B; }
inline friend Line operator+(const Line &a,const Line &b){ return Line(a.k+b.k,a.b+b.b); }
inline void operator+=(const Line &a){ k+=a.k,b+=a.b; }
inline friend Line operator*(const Line &a,const ll &b){ return Line(a.k*b,a.b*b); }
inline ll getv(ll x){ return k*x+b; }
};
int n,q,a[N];
struct Segment_Tree{
#define ls (rt<<1)
#define rs (rt<<1|1)
Line sum[N<<2],tag[N<<2];
inline void pushup(int rt){
sum[rt]=sum[ls]+sum[rs];
}
inline void pushtag(int rt,int l,int r,Line v){
sum[rt]+=v*(r-l+1);
tag[rt]+=v;
}
inline void pushdown(int rt,int l,int r){
if(tag[rt].k||tag[rt].b){
int mid=l+r>>1;
pushtag(ls,l,mid,tag[rt]);
pushtag(rs,mid+1,r,tag[rt]);
tag[rt]=Line();
}
}
inline void build(int rt,int l,int r){
if(l==r){
sum[rt]=Line(a[l],a[l]);
return ;
}
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushup(rt);
}
inline void modify(int rt,int l,int r,int p,Line v){
if(l==r){
sum[rt]+=v;
return ;
}
pushdown(rt,l,r);
int mid=l+r>>1;
if(p<=mid) modify(ls,l,mid,p,v);
else modify(rs,mid+1,r,p,v);
pushup(rt);
}
inline void modify(int rt,int l,int r,int L,int R,Line v){
if(L<=l&&r<=R){
pushtag(rt,l,r,v);
return ;
}
pushdown(rt,l,r);
int mid=l+r>>1;
if(L<=mid) modify(ls,l,mid,L,R,v);
if(R>mid) modify(rs,mid+1,r,L,R,v);
pushup(rt);
}
inline ll query(int rt,int l,int r,int L,int R,ui x){
if(L<=l&&r<=R)
return sum[rt].getv(x);
pushdown(rt,l,r);
int mid=l+r>>1;
ll ans=0;
if(L<=mid) ans+=query(ls,l,mid,L,R,x);
if(R>mid) ans+=query(rs,mid+1,r,L,R,x);
pushup(rt);
return ans;
}
}T;
哈希表
template<class P,class Q>
class HashTable{
static const int mod=5e5+9,L=mod+10;
int head[L],nxt[N],siz;
P val[N];
Q sav[N],z;
public:
inline void clear(){
for(int i=1;i<=siz;i++){
head[val[i]%mod]=0,nxt[i]=val[i]=0;
Q tmp=z;
swap(sav[i],tmp);
}
siz=0;
}
inline void insert(P y){
val[++siz]=y;
nxt[siz]=head[y%mod];
head[y%mod]=siz;
}
inline Q &operator[](const P y){
int x=y%mod;
for(int i=head[x];i;i=nxt[i])
if(val[i]==y)
return sav[i];
insert(y);
return sav[siz];
}
inline bool count(const P y){
int x=y%mod;
for(int i=head[x];i;i=nxt[i])
if(val[i]==y)
return 1;
return 0;
}
};
稀疏矩阵乘法
struct Matrix{
vector<vector<int>>a;
int n,m;
inline void init(int N,int M){
n=N,m=M;
a.resize(n);
for(int i=0;i<n;i++)
a[i].resize(m,0);
}
inline vector<int>& operator[](int x){ return a[x]; }
inline friend Matrix operator*(Matrix &a,Matrix &b){
Matrix c;
c.init(a.n,b.m);
for(int k=0;k<a.m;k++){
int pos[V],top=0;
for(int j=0;j<b.m;j++)
if(b[k][j])
pos[++top]=j;
for(int i=0;i<c.n;i++)
if(a[i][k])
for(int j=1;j<=top;j++)
inc(c[i][pos[j]],1ll*a[i][k]*b[k][pos[j]]%mod);
}
return c;
}
};
反射容斥
inline int Calc(int n,int m,int l,int r){
int ans=0;
for(int k=0;n-k*(r-l)>=0;k++) ans=add(ans,C(n+m,n-k*(r-l)));
for(int k=0;n-k*(r-l)+r>=0;k++) ans=dec(ans,C(n+m,n-k*(r-l)+r));
for(int k=-1;n-k*(r-l)<=n+m;k--) ans=add(ans,C(n+m,n-k*(r-l)));
for(int k=-1;n-k*(r-l)+r<=n+m;k--) ans=dec(ans,C(n+m,n-k*(r-l)+r));
return ans;
}
计算从 \((0,0)\) 到达 \((n,m)\) 且不经过 \(y=x+l\) 和 \(y=x+r\) 的路径数。
时间复杂度 \(O(\dfrac{n+m}{r-l})\)。
最近公共祖先
struct ST_table{
int dep[N],dfn[N],tim,st[19][N];
inline void dfs(int rt,int f){
dep[rt]=dep[f]+1;
st[0][dfn[rt]=++tim]=f;
for(int i=head[rt];i;i=a[i].nxt){
int t=a[i].to;
if(t==f) continue;
dfs(t,rt);
}
}
inline int cmp(int x,int y){
return dep[x]<dep[y]?x:y;
}
inline void init(){
dfs(1,0);
for(int i=1;(1<<i)<=n;i++)
for(int j=1;j+(1<<i)-1<=n;j++)
st[i][j]=cmp(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
inline int LCA(int x,int y){
if(x==y) return x;
x=dfn[x],y=dfn[y];
if(x>y) swap(x,y);
x++;
int i=__lg(y-x+1),p=1<<i;
return cmp(st[i][x],st[i][y-p+1]);
}
inline int dis(int u,int v){
return dep[u]+dep[v]-2*dep[LCA(u,v)];
}
}st;
虚树
namespace FT{
inline bool cmp(int u,int v){
return st.dfn[u]<st.dfn[v];
}
int head[N],cnt;
struct EdgeT{
int to,nxt;
}a[N];
inline void adde(int u,int v){
cnt++;
a[cnt].to=v;
a[cnt].nxt=head[u];
head[u]=cnt;
}
vector<int>c;
inline void build(){
sort(c.begin(),c.end(),cmp);
c.erase(unique(c.begin(),c.end()),c.end());
int s=c.size();
for(int i=1;i<s;i++)
c.push_back(st.LCA(c[i-1],c[i]));
sort(c.begin(),c.end(),cmp);
c.erase(unique(c.begin(),c.end()),c.end());
for(int i=1;i<c.size();i++){
int l=st.LCA(c[i-1],c[i]);
adde(l,c[i]);
}
}
inline int solve(vector<int>t){
c=t;
build();
cnt=0;
for(auto tmp:c)
head[tmp]=0;
return tmp;
}
}

浙公网安备 33010602011771号