常用黑盒

扫描线维护区间 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;
    }
}
posted @ 2024-02-26 19:39  ffffyc  阅读(60)  评论(0)    收藏  举报  来源