templates

templates

前言

2024.11.25 此文用于整理板子

动态规划

动态动态规划 DDP

namespace wing_heart {
	constexpr int N=1e6+7,inf=0x3f3f3f3f;
	int n,m;
	int w[N];
	vector<int> son[N];
	int f[N][2],g[N][2];
	int siz[N];
	int gson[N];
	int top[N];
	int end[N];
	int dfn[N],dfn0,idfn[N];
	int fa[N];
	struct mat {
		int x[2][2];
		void init() { x[0][1]=x[1][0]=-inf; } // 单位矩阵
		int* operator [] (int pos) { return x[pos]; }
		mat operator * (mat &b) {
			mat c;
			rep(i,0,1) rep(j,0,1) {
				c[i][j]=max(x[i][0]+b[0][j],x[i][1]+b[1][j]);
			}
			return c;
		}
	}s[N],ss[N];
	struct mat2 {
		int x[2];
		int& operator [] (int pos) { return x[pos]; }
	};
	void dfs0(int u,int f) {
		fa[u]=f;
		siz[u]=1;
		for(int v : son[u]) if(v^f) {
			dfs0(v,u);
			siz[u]+=siz[v];
			if(siz[v]>siz[gson[u]]) gson[u]=v;
		}
	}
	void dfs1(int u,int tp) {
		top[u]=tp;
		dfn[u]=++dfn0;
		idfn[dfn0]=u;
		end[u]=dfn0;
		f[u][1]=w[u];
		if(gson[u]) {
			dfs1(gson[u],tp);
			end[u]=end[gson[u]];
		}
		for(int v : son[u]) if(v^fa[u] && v^gson[u]) {
			dfs1(v,v);
			f[u][0]+=max(f[v][0],f[v][1]);
			f[u][1]+=f[v][0];
		}
		g[u][0]=f[u][0], g[u][1]=f[u][1];
		if(gson[u]) f[u][0]+=max(f[gson[u]][0],f[gson[u]][1]), f[u][1]+=f[gson[u]][0];
		s[u]={g[u][0],g[u][0],g[u][1],-inf};
	}
	int rt;
	int up[N];
	int ch[N][2];
	void pushup(int u) {
		ss[u]=ss[ch[u][0]]*s[u]*ss[ch[u][1]];
		// 想清楚是先乘左儿子还是右儿子。
	}
	int _build(int l,int r) {
		int sum=0,tmp=0;
		rep(i,l,r) sum+=siz[idfn[i]]-siz[gson[idfn[i]]];
		rep(i,l,r) {
			int u=idfn[i];
			tmp+=siz[u]-siz[gson[u]];
			if(tmp*2>sum) {
				if(l<=i-1) ch[u][0]=_build(l,i-1), up[ch[u][0]]=u;
				if(i+1<=r) ch[u][1]=_build(i+1,r), up[ch[u][1]]=u;
				pushup(u);
				return u;
			}
		}
		return 0;
	}
	int build(int p) {
		rep(i,dfn[p],end[p]) {
			int u=idfn[i];
			for(int v : son[u]) if(v^gson[u] && v^fa[u]) up[build(v)] = u;
		}
		return _build(dfn[p], end[p]);
	}
	void change(int u,int x) {
		s[u][1][0]+=x-w[u];
		w[u]=x;
		while(u) {
			int fa = up[u];
			if(fa && ch[fa][0]!=u && ch[fa][1]!=u) { // 虚边
				mat bef = ss[u]; // before
				pushup(u);
				mat aft = ss[u]; // after
				static mat2 fub,fua; //f_u before/after 
				fub={max(bef[0][0],bef[0][1]),max(bef[1][0],bef[1][1])};
				fua={max(aft[0][0],aft[0][1]),max(aft[1][0],aft[1][1])};
				s[fa][0][0]+=max(fua[0],fua[1]) - max(fub[0],fub[1]);
				s[fa][0][1]+=max(fua[0],fua[1]) - max(fub[0],fub[1]);
				s[fa][1][0]+=fua[0]-fub[0];
			} else pushup(u);
			u=fa;
		}
	}
	int laans;
	void main() {
		sf("%d%d",&n,&m);
		rep(i,1,n) sf("%d",&w[i]);
		rep(i,1,n-1) {
			int u,v;
			sf("%d%d",&u,&v);
			son[u].push_back(v);
			son[v].push_back(u);
		}
		dfs0(1,0);
		dfs1(1,1);
		ss[0].init();
		rt=build(1);
		while(m--) {
			int u,x;
			sf("%d%d",&u,&x);
			u^=laans;
			change(u,x);
			pf("%d\n",laans = max(ss[rt][0][0],ss[rt][1][0]));
		}
	}
}

字符串

KMP

namespace KMP {
    constexpr int N=1e6+7;
    char s[N],t[N];
    int lens,lent;
    int nxt[N];// 后缀 i 的 border 长度
    void main() {
        sf("%s%s",s+1,t+1);
        lens=strlen(s+1), lent=strlen(t+1);
        rep(i,2,lent) {
            int &p=nxt[i]=nxt[i-1];
            while(p && t[i]!=t[p+1]) p=nxt[p];
            if(t[i]==t[p+1]) ++p;
        }
        int itt=0;// 已经匹配了 itt 位
        rep(i,1,lens) {
            while(itt && s[i]!=t[itt+1]) itt=nxt[itt];
            if(s[i]==t[itt+1]) ++itt;
            if(itt==lent) pf("%d\n",i-lent+1);
        }
        rep(i,1,lent) pf("%d ",nxt[i]);
    }
}

manacher

namespace manacher {
    constexpr int N=1.1e7+7;
    int n;
    char s[N],t[N<<1];
    void init() {
        t[1]='#', t[2]='$';
        rep(i,1,n) t[(i<<1)+1]=s[i], t[(i<<1|1)+1]='$';
        t[(n<<1|1)+2]='&';
    }
    int p[N<<1];
    int m;
    int ans;
    int r,mid;
    void solve() {
        r=mid=1;
        rep(i,2,m) {
            int j=(mid<<1)-i;
            if(i<=r) p[i]=min(p[j],r-i);
            while(t[i-p[i]-1] == t[i+p[i]+1]) ++p[i];
            if(p[i]+i>r) r=p[i]+i, mid=i;
            ans=max(ans,p[i]);
        }
    }
    void main() {
        sf("%s",s+1);
        n=strlen(s+1);
        init();
        m=(n<<1|1)+2;
        solve();
        pf("%d\n",ans);
    }
}

SA 后缀数组

namespace SA {
    constexpr int N=1e6+7;
    char s[N];
    int n,m,p;
    int rk[N],sa[N];
    int tmprk[N];
    int cnt[N];
    int id[N];
    void main() {
        sf("%s",s+1);
        n=strlen(s+1);
        m=128;
        rep(i,1,n) cnt[rk[i]=s[i]]++;
        rep(i,1,m) cnt[i]+=cnt[i-1];
        per(i,n,1) sa[cnt[rk[i]]--]=i;
        for(int w=1;;w<<=1,m=p) {
            int cur=0;
            rep(i,n-w+1,n) id[++cur]=i;
            rep(i,1,n) if(sa[i]>w) id[++cur]=sa[i]-w;
            memset(cnt,0,sizeof(cnt));
            rep(i,1,n) cnt[rk[i]]++;
            rep(i,1,m) cnt[i]+=cnt[i-1];
            per(i,n,1) sa[cnt[rk[id[i]]]--]=id[i];
            p=0;
            memcpy(tmprk,rk,sizeof(rk));
            rep(i,1,n) {
                if(tmprk[sa[i]]==tmprk[sa[i-1]] && tmprk[sa[i]+w]==tmprk[sa[i-1]+w]) rk[sa[i]]=p;
                else rk[sa[i]]=++p;
            }  
            if(p==n) break;
        }
        rep(i,1,n) pf("%d ",sa[i]);
    }
}

SAM 后缀自动机

struct sam {
    int last=1,cnt=1;
    int ch[N<<1][26],fa[N<<1],l[N<<1];
    void insert(int c) {
        int p=last,np=++cnt;
        last=np;
        l[np]=l[p]+1;
        for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
        if(!p) fa[np]=1;
        else {
            int q=ch[p][c];
            if(l[p]+1==l[q]) fa[np]=q;
            else {
                int nq=++cnt;
                l[nq]=l[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[nq]=fa[q],fa[q]=fa[np]=nq;
                for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
        size[np]=1;
    }
};

数学

数论

exgcd

l x,y;
ll exgcd(int a,int b) {
	if(!b) {
		x=1, y=0; 
		return a;
	}
	int d=exgcd(b,a%b);
	int t=x;
	x=y; 
	y=t-a/b*y;
	return d;
}
void solve(int a,int b,int c) { // ax+by=c
	int g=exgcd(a,b);
	if(c%g) return puts("-1"), void(0); // 无整数解
	x*=c/g, y*=c/g;
	ll tx=b/g, ty=a/g;
	ll k=ceil(1.0*(-x+1)/tx);
	x+=k*tx, y-=k*ty;
	if(y<=0) { // 无 x,y 均是正整数的解
		ll ymn=y+ty*ceil(1.0*(-y+1)/ty);
		pf("%lld %lld\n",x,ymn); // xmin,ymin
		return;
	} 
	ll ky=ceil(1.0*(-y+1)/ty);
	pf("%lld %lld %lld %lld %lld\n",(y-1)/ty+1,x,y+ty*ky,x-ky*tx,y); // 正整数解的个数,xmin,ymin,xmax,ymax
}

线性代数

线性基(插入)

int n;
ll a,p[N];
void insert(ll x) {
    per(i,bit,0) {
        if(!(x&(1ll<<i))) continue;
        if(!p[i]) return p[i]=x, void(0);
        x^=p[i];
    }
}

行列式

void _swap(int x,int y) {
    rep(i,1,n) swap(a[x][i],a[y][i]);
    f^=1;
}
void gauss() {
    rep(i,1,n) {
        rep(j,i+1,n) {
            while(a[i][i]) {
                int K=a[j][i]/a[i][i];
                rep(k,i,n) {
                    _add(a[j][k],p-mul(K,a[i][k]));
                }
                _swap(i,j);
            }
            _swap(i,j);
        }
    }
}
int calc() {
    int ans=1;
    rep(i,1,n) _mul(ans,a[i][i]);
    return f ? add(p,-ans) : ans;
}
void main() {   
    sf("%d%d",&n,&p);
    rep(i,1,n) rep(j,1,n) sf("%d",&a[i][j]), (a[i][j]+=p)%=p;
    gauss();
    pf("%d\n",calc());
}

多项式

FWT

函数:

void calc() { rep(i,0,n-1) _mul(a[i],b[i]); }
void OR(int *f,int x=1) {
    for(int o=2,k=1; o<=n; o<<=1,k<<=1)     
        for(int i=0; i<n; i+=o)
            rep(j,0,k-1) _add(f[i+j+k],mul(f[i+j],x));
}
void AND(int *f,int x=1) {
    for(int o=2,k=1; o<=n; o<<=1,k<<=1)     
        for(int i=0; i<n; i+=o)
            rep(j,0,k-1) _add(f[i+j],mul(f[i+j+k],x));
}
void XOR(int *f,int x=1) {
    for(int o=2,k=1; o<=n; o<<=1,k<<=1)     
        for(int i=0; i<n; i+=o)
            rep(j,0,k-1) 
                _add(f[i+j],f[i+j+k]), f[i+j+k]=add(f[i+j],mod-add(f[i+j+k],f[i+j+k])), _mul(f[i+j],x), _mul(f[i+j+k],x);
}

调用方式:

OR(a), OR(b), calc(), OR(a,mod-1);
AND(a), AND(b), calc(), AND(a,mod-1);
XOR(a), XOR(b), calc(), XOR(a,ksm(2));

数据结构

线段树

zkw 线段树

struct zkw {
	int p;
	ll sum[N<<2],tag[N<<2];
	void pushup(int u,int siz) { sum[u]=sum[u<<1]+sum[u<<1|1]+tag[u]*siz; }
	void build() {
		p=1;
		while(p-2<n) p<<=1;
		rep(i,1,n) sum[p+i]=a[i];
		per(i,p-1,1) sum[i]=sum[i<<1]+sum[i<<1|1];
	}
	void update(int l,int r,ll x) {
		int L=p+l-1,R=p+r+1;
		int siz=1;
		while(L^R^1) {
			if((L&1)^1) sum[L^1]+=x*siz, tag[L^1]+=x;
			if(R&1) sum[R^1]+=x*siz, tag[R^1]+=x;
			L>>=1, R>>=1, siz<<=1;
			pushup(L,siz),pushup(R,siz);
		} 
		for(L>>=1,siz<<=1;L;L>>=1,siz<<=1) pushup(L,siz);
	}
	ll query(int l,int r) {
		ll s=0;
		int L=p+l-1,R=r+p+1;
		int sizl=0,sizr=0,siz=1;
		while(L^R^1) {
			if((L&1)^1) s+=sum[L^1], sizl+=siz;
			if(R&1) s+=sum[R^1], sizr+=siz;
			L>>=1, R>>=1, siz<<=1;
			s+=tag[L]*sizl+tag[R]*sizr;
		}
		for(L>>=1,sizl+=sizr;L;L>>=1) s+=tag[L]*sizl;
		return s;
	}
};

平衡树

fhq 平衡树

const int N=1e5+7,V=1e9;
int n;
int opt,x;
mt19937 rd(time(0));
struct node{
    int val,pri,siz;
    int ch[2];
};
struct fhq_treap{
    int cnt,rt;
    node tr[N];
    int newnode(int x){
        tr[++cnt]={x,(int)rd()%V,1};
        return cnt;
    }
    void pushup(int u){
        tr[u].siz=tr[tr[u].ch[0]].siz+tr[tr[u].ch[1]].siz+1;
    }
    void split(int u,int &x,int &y,int w){
        if(!u) return x=y=0,void();
        if(tr[u].val<=w){
            x=u,split(tr[u].ch[1],tr[u].ch[1],y,w);
        }else{
            y=u,split(tr[u].ch[0],x,tr[u].ch[0],w);
        }
        pushup(u);
    }
    int merge(int x,int y){
        if(!x||!y) return x+y;
        if(tr[x].pri<tr[y].pri) {
            tr[x].ch[1]=merge(tr[x].ch[1],y);
            pushup(x);
            return x;
        }else{
            tr[y].ch[0]=merge(x,tr[y].ch[0]);
            pushup(y);
            return y;
        }
    }
    void insert(int w){
        int x,y;
        split(rt,x,y,w);
        rt=merge(x,merge(newnode(w),y));
    }
    void del(int w){
        int x,y;
        split(rt,x,y,w);
        int z;
        split(x,x,z,w-1);
        z=merge(tr[z].ch[0],tr[z].ch[1]);
        rt=merge(x,merge(z,y));
    }
    void find_by_key(int w){
        int x,y;
        split(rt,x,y,w-1);
        pf("%d\n",tr[x].siz+1);
        rt=merge(x,y);
    }
    int kth(int u,int k){
        if(tr[tr[u].ch[0]].siz+1==k) return tr[u].val;
        if(k<=tr[tr[u].ch[0]].siz) return kth(tr[u].ch[0],k);
        return kth(tr[u].ch[1],k-tr[tr[u].ch[0]].siz-1);
    }
    void find_by_rank(int k){
        pf("%d\n",kth(rt,k));
    }
    void find_pre(int w){
        int x,y;
        split(rt,x,y,w-1);
        int now=x;
        while(tr[now].ch[1]) now=tr[now].ch[1];
        pf("%d\n",tr[now].val);
        rt=merge(x,y);
    }
    void find_next(int w){
        int x,y;
        split(rt,x,y,w);
        int now=y;
        while(tr[now].ch[0]) now=tr[now].ch[0];
        pf("%d\n",tr[now].val);
        rt=merge(x,y);
    }
};

树套树

线段树套平衡树

namespace shutaoshu {
    constexpr int N=5e4+7,V=1e8,inf=2147483647;
    int n,m;
    int a[N];
    int opt;
    int l,r,pos,k;
    mt19937 rd(random_device{}());
    struct node {
        int val,rk;
        int siz;
        int ls,rs;
    }tr[N*60];
    int cnt;
    int newnode(int val) { tr[++cnt]={val,(int)rd(),1}; return cnt; }
    struct fhq_tree {
        int rt;
        void pushup(int u) { tr[u].siz=tr[tr[u].ls].siz+tr[tr[u].rs].siz+1; }
        void split(int u,int &x,int &y,int w) {// 将小于等于 w 的分到 x,大于 w 的分到 y
            if(!u) return x=y=0, void(0);
            if(tr[u].val<=w) {
                x=u, split(tr[u].rs,tr[u].rs,y,w);
            } else {
                y=u, split(tr[u].ls,x,tr[u].ls,w);
            }
            pushup(u);
        }
        int merge(int x,int y) {
            if(!x || !y) return x+y;
            if(tr[x].rk < tr[y].rk) {
                tr[x].rs=merge(tr[x].rs,y);
                pushup(x);
                return x;
            } else {
                tr[y].ls=merge(x,tr[y].ls);
                pushup(y);
                return y;
            }
        }
        void insert(int val) {// 插入值 val
            int x,y;
            split(rt,x,y,val);
            rt=merge(x,merge(newnode(val),y));
        }
        void delback(int &u) {// 删除平衡树最大的节点
            if(!tr[u].rs) return u=tr[u].ls, void(0);
            delback(tr[u].rs);
            pushup(u);
        }
        void del(int val) {// 删除值 val
            int x,y;
            split(rt,x,y,val);
            delback(x);
            rt=merge(x,y);
        }
        int query(int u,int w) {// 返回 u 的子树中小于等于 w 的值的个数
            if(!u) return 0;
            if(tr[u].val<=w) return tr[tr[u].ls].siz+1+query(tr[u].rs,w);
            return query(tr[u].ls,w);
        }
        int get_pre(int val) {// 找严格小于 val 的前驱
            int x,y;
            split(rt,x,y,val-1);
            int p=x;
            while(tr[p].rs) p=tr[p].rs;
            int ans;
            if(p) ans=tr[p].val;
            else ans=-inf;
            rt=merge(x,y);
            return ans;
        }
        int get_nex(int val) {// 找严格大于 val 的后继
            int x,y;
            split(rt,x,y,val);
            int p=y;
            while(tr[p].ls) p=tr[p].ls;
            int ans;
            if(p) ans=tr[p].val;
            else ans=inf;
            rt=merge(x,y);
            return ans;
        }
    };
    struct segtree {
        fhq_tree tr[N<<2];
        void build(int u=1,int l=1,int r=n) {
            rep(i,l,r) tr[u].insert(a[i]);
            if(l==r) return;
            int mid=(l+r)>>1;
            build(u<<1,l,mid), build(u<<1|1,mid+1,r);
        }
        int query(int L,int R,int val,int u=1,int l=1,int r=n) {// 返回区间小于等于 val 的元素个数
            if(l>=L && r<=R) return tr[u].query(tr[u].rt,val);
            int s=0;
            int mid=(l+r)>>1;
            if(L<=mid) s+=query(L,R,val,u<<1,l,mid);
            if(mid+1<=R) s+=query(L,R,val,u<<1|1,mid+1,r);
            return s;
        }
        void change(int pos,int val,int u=1,int l=1,int r=n) {
            tr[u].del(a[pos]), tr[u].insert(val);
            if(l==r) return;
            int mid=(l+r)>>1;
            if(pos<=mid) change(pos,val,u<<1,l,mid);
            else change(pos,val,u<<1|1,mid+1,r);
        }
        int get_pre(int L,int R,int val,int u=1,int l=1,int r=n) {
            if(l>=L && r<=R) return tr[u].get_pre(val);
            int mid=(l+r)>>1;
            int s=-inf;
            if(L<=mid) s=get_pre(L,R,val,u<<1,l,mid);
            if(mid+1<=R) s=max(s,get_pre(L,R,val,u<<1|1,mid+1,r));
            return s;
        }
        int get_nex(int L,int R,int val,int u=1,int l=1,int r=n) {
            if(l>=L && r<=R) return tr[u].get_nex(val);
            int mid=(l+r)>>1;
            int s=inf;
            if(L<=mid) s=get_nex(L,R,val,u<<1,l,mid);
            if(mid+1<=R) s=min(s,get_nex(L,R,val,u<<1|1,mid+1,r));
            return s;
        }
    }T;
    void init() {
        T.build();
    }
    int get_rk_by_val(int l,int r,int val) {
        return T.query(l,r,val-1)+1;
    }
    int get_val_by_rk(int l,int r,int k) {
        int L=0,R=V;
        while(L<R) {
            int mid=(L+R+1)>>1;
            if(get_rk_by_val(l,r,mid)>k) R=mid-1;
            else L=mid;
        }
        return L;
    }
    void change_val_by_pos(int pos,int val) {
        T.change(pos,val);
        a[pos]=val;
    }
    int get_pre_by_val(int l,int r,int val) {
        return T.get_pre(l,r,val);
    }
    int get_nex_by_val(int l,int r,int val) {
        return T.get_nex(l,r,val);
    }
    void main() {
        sf("%d%d",&n,&m);
        rep(i,1,n) sf("%d",&a[i]);
        init();
        rep(i,1,m) {
            sf("%d",&opt);
            switch (opt) {
                case 1 : sf("%d%d%d",&l,&r,&k); pf("%d\n",get_rk_by_val(l,r,k)); break;
                case 2 : sf("%d%d%d",&l,&r,&k); pf("%d\n",get_val_by_rk(l,r,k)); break;
                case 3 : sf("%d%d",&pos,&k); change_val_by_pos(pos,k); break;
                case 4 : sf("%d%d%d",&l,&r,&k); pf("%d\n",get_pre_by_val(l,r,k)); break;
                case 5 : sf("%d%d%d",&l,&r,&k); pf("%d\n",get_nex_by_val(l,r,k)); break;
            }
        }
    }
}

树论

树链剖分

重链剖分

struct tree {
	int fa[N],siz[N],gson[N],dep[N];
	int dfn[N],eddfn[N],cnt,idfn[N];
	int top[N];
	void dfs(int u,int f) {
		fa[u]=f;
		dep[u]=dep[f]+1;
		siz[u]=1;
		for(int i=head[u]; i; i=e[i].ne) {
			int v=e[i].to;
			if(v==f) continue;
			dfs(v,u);
			siz[u]+=siz[v];
			if(siz[v]>siz[gson[u]]) gson[u]=v;
		}
	}
	void dfs(int u) {
		dfn[u]=eddfn[u]=++cnt;
		idfn[cnt]=u;
		if(gson[u]) top[gson[u]]=top[u], dfs(gson[u]);
		for(int i=head[u]; i; i=e[i].ne) {
			int v=e[i].to;
			if(v==fa[u] || v==gson[u]) continue;
			top[v]=v, dfs(v);
		}
		eddfn[u]=cnt;
	}
	int tr[N<<2],tag[N<<2];
	int p;
	void build() {
		p=1;
		while(p-2<n) p<<=1;
		rep(i,1,n) tr[p+i]=a[idfn[i]];
		per(i,p-1,1) tr[i]=add(tr[i<<1],tr[i<<1|1]);
	}
	void init() {
		dfs(rt,0);
		top[rt]=rt;
		dfs(rt);
		build();
	}
	void maketag(int u,int x,int siz) { _add(tr[u],1ll*x*siz%mod), _add(tag[u],x); }
	void pushup(int u,int siz) { tr[u]=add(add(tr[u<<1],tr[u<<1|1]),1ll*siz*tag[u]%mod); }
	void _update(int l,int r,int x) {
		l=p+l-1, r=p+r+1;
		int siz=1;
		while(l^r^1) {
			if((l&1)^1) maketag(l^1,x,siz);
			if(r&1) maketag(r^1,x,siz);
			l>>=1, r>>=1, siz<<=1;
			pushup(l,siz), pushup(r,siz);
		} 
		for(l>>=1, siz<<=1; l; l>>=1, siz<<=1) pushup(l,siz);
	}
	int _query(int l,int r) {
		l=p+l-1, r=p+r+1;
		int sizl=0,sizr=0,siz=1;
		int s=0;
		while(l^r^1) {
			if((l&1)^1) _add(s,tr[l^1]), sizl+=siz;
			if(r&1) _add(s,tr[r^1]), sizr+=siz;
			l>>=1, r>>=1, siz<<=1;
			_add(s,1ll*tag[l]*sizl%mod), _add(s,1ll*tag[r]*sizr%mod);
		}
		for(l>>=1, sizl+=sizr; l; l>>=1) _add(s,1ll*tag[l]*sizl%mod);
		return s;
	}
	void update(int u,int v,int x) {
		while(top[u]^top[v]) {
			if(dep[top[u]]<dep[top[v]]) swap(u,v);
			_update(dfn[top[u]],dfn[u],x), u=fa[top[u]];
		}
		if(dfn[u]>dfn[v]) swap(u,v);
		_update(dfn[u],dfn[v],x);
	}
	void update(int u,int x) {
		_update(dfn[u],eddfn[u],x);
	}
	int query(int u,int v) {
		int s=0;
		while(top[u]^top[v]) {
			if(dep[top[u]]<dep[top[v]]) swap(u,v);
			_add(s,_query(dfn[top[u]],dfn[u])), u=fa[top[u]];
		}
		if(dfn[u]>dfn[v]) swap(u,v);
		_add(s,_query(dfn[u],dfn[v]));
		return s;
	}
	int query(int u) {
		return _query(dfn[u],eddfn[u]);
	}
};

全局平衡二叉树

int gson[N],siz[N];
void dfs(int u) {	
	siz[u]=1;
	for(int v : son[u]) {
		dfs(v);
		siz[u]+=siz[v];
		if(siz[v]>siz[gson[u]]) gson[u]=v;
	}
}
int t[N],ts[N],ss[N],ch[N][2],f[N];//装重链的桶、加权前缀和、二叉树子树大小、二叉树两个儿子、全局平衡二叉树父亲
int _build(int l,int r) {
	int mid=((ts[r]-ts[l])>>1)+ts[l];
	int k=lower_bound(ts+l+1,ts+r+1,mid)-ts;
	int u=t[k];
	ss[u]=r-l;
	if(l<k-1) ch[u][0]=_build(l,k-1), f[ch[u][0]]=u;
	if(k<r) ch[u][1]=_build(k,r), f[ch[u][1]]=u;
	return u;
}
int build(int u) {
	int x=u;
	do {
		for(int v : son[x]) if(v!=gson[x]) f[build(v)]=x;
	} while(x=gson[x]);
	x=0;
	do {
		t[++x]=u;
		ts[x]=ts[x-1]+siz[u]-siz[gson[u]];
	} while(u=gson[u]);
	return _build(0,x);
}
void init() {
	dfs(1);
	build(1);
}
int tg[N],sum[N];//单个二叉树 子树标记(永久化)、子树和
void add(int u) {
	bool fl=1;
	int x=0;//当前二叉树的当前子树有多少点要加
	while(u) {
		_add(sum[u],x);
		if(fl) {//如果要 u 的左子树(包括 u)
			_add(tg[u],1);//整棵树打标记
			if(ch[u][1]) _add(tg[ch[u][1]],mod-1);//右子树不打标记,容斥掉
			_add(x,ss[ch[u][0]]+1);//更新祖先时用
			_add(sum[u],mod-ss[ch[u][1]]);//因为标记永久化了,容斥掉不要的部分
		}
		fl=u!=ch[f[u]][0];
		if(fl && u!=ch[f[u]][1]) x=0;//跳过轻边
		u=f[u];
	}
}
int query(int u) {
	int ans=0;
	int fl=1;
	int x=0;//当前子树要了多少个点
	while(u) {
		if(fl) {//如果要左子树和 u 自己
			_add(ans,add(sum[u],mod-sum[ch[u][1]]));
			_add(ans,mod-mul(tg[ch[u][1]],ss[ch[u][1]]));
			_add(x,ss[ch[u][0]]+1);
		}
		_add(ans,mul(x,tg[u]));
		fl=u!=ch[f[u]][0];
		if(fl && u!=ch[f[u]][1]) x=0;
		u=f[u];
	}
	return ans;
}

图论

简单图论

欧拉路径

namespace oulalujing {
constexpr int N=1e5+7,M=2e5+7;
	int n,m;
	vector<int> son[N];
	int out[N],in[N];
	int rt;
	int head[N];
	int st[M],top;
	void dfs(int u) {
		for(int &i = head[u]; i<(int)son[u].size();) {
			dfs(son[u][i++]);
		}
		// 在函数 return 的时候再存,可以保证存出的路是链
		st[top++]=u;
	}
	// 找字典序最小的欧拉路径
    void main() {
		sf("%d%d",&n,&m);
		rep(i,1,m) {
			int u,v;
			sf("%d%d",&u,&v);
			son[u].push_back(v);
			++out[u], ++in[v];
		}
		rep(i,1,n) {
			// 按照字典序排序
			sort(son[i].begin(),son[i].end());
			if(abs(in[i]-out[i])>1) {
				puts("No");
				exit(0);
			}
			// 找起点
			if(out[i]>in[i]) {
				if(rt) {
					puts("No");
					exit(0);
				}
				rt=i;
			}
		}
		dfs(rt ? rt : 1);
		if(top==m+1) {
			while(top) pf("%d ",st[--top]);
		} else puts("No");
    }
}

连通性相关

割点和桥

void tarjan(int rt,int u,int f) {
    dfn[u]=low[u]=++cnt;
    for(int v : to[u]) {
        if(!dfn[v]) {
            tarjan(rt,v,u), low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u]) ans.push_back({u,v});
        }else if(v!=f) low[u]=min(low[u],dfn[v]);
    }
}
割点
void tarjan(int rt,int u,int f) {
	dfn[u]=low[u]=++cnt;
	int son=0;
	for(int v : to[u]) {
		if(!dfn[v]) {
			++son, tarjan(rt,v,u), low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u] && u!=rt && !isans[u]) isans[u]=1, ans.push_back(u);
		}else if(v!=f) low[u]=min(low[u],dfn[v]);
	}
	if(son>=2 && u==rt) isans[u]=1, ans.push_back(u);
}
强连通分量
void tarjan(int u) {
    dfn[u]=low[u]=++dfn0;
    st[++top]=u;
    for(int v : to[u]) {
        if(!dfn[v]) {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(!num[v]) {
            low[u]=min(low[u],low[v]);//与 dfn[v] 等价
        }
    }
    if(low[u]==dfn[u]) {
        ++cnt;
        while(st[top+1]!=u) scc[cnt].push_back(st[top]), num[st[top]]=cnt, --top;
    }
}

网络流

dinic 算法

bool bfs() {
    queue<int> q;
    memset(dis,0x3f,sizeof(dis));
    memcpy(cur,head,sizeof(cur));
    dis[s]=0;
    q.push(s);
    while(q.size()) {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].ne) {
            int v=e[i].to;
            if(e[i].f && dis[v]>dis[u]+1) {
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    return dis[t]!=inf;
}
int dfs(int u,int sum) {
    if(u==t) return sum;
    int ans=0;
    for(int i=cur[u];i && sum;i=e[i].ne) {
        cur[u]=i;
        int v=e[i].to;
        if(e[i].f && dis[v]==dis[u]+1) {
            int x=dfs(v,min(sum,e[i].f));
            if(x) sum-=x, ans+=x, e[i].f-=x, e[i^1].f+=x;
            else dis[v]=-1;
        }
    }
    return ans;
}
int dinic() {
    int flow=0;
    int x=0;
    while(bfs()) {
        while(x=dfs(s,inf)) flow+=x;
    }
    return flow;
}

上下界网络流

有源汇上下界最大流

代码无法过编。

int n,m;
int cnt=1;
int head[N];
int in[N],out[N];
int s,t,s1,s2,t1,t2;
int sum;
int dis[N];
int cur[N];
struct edge {
    int to,f,ne;
}e[M<<1];
void addedge(int u,int v,int f) {
    e[++cnt]={v,f,head[u]}, head[u]=cnt;
    e[++cnt]={u,0,head[v]}, head[v]=cnt;
}
bool bfs() {
    queue<int> q;
    memset(dis,0x3f,sizeof(dis));
    memcpy(cur,head,sizeof(cur));
    dis[s]=0;
    q.push(s);
    while(q.size()) {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].ne) {
            int v=e[i].to;
            if(e[i].f && dis[v]>dis[u]+1) {
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    return dis[t]!=inf;
}
int dfs(int u,int sum) {
    if(u==t) return sum;
    int ans=0;
    for(int i=cur[u];i && sum;i=e[i].ne) {
        cur[u]=i;
        int v=e[i].to;
        if(e[i].f && dis[v]==dis[u]+1) {
            int x=dfs(v,min(sum,e[i].f));
            if(x) sum-=x, ans+=x, e[i].f-=x, e[i^1].f+=x;
            else dis[v]=-1;
        }
    }
    return ans;
}
int dinic() {
    int flow=0;
    int x=0;
    while(bfs()) {
        while(x=dfs(s,inf)) flow+=x;
    }
    return flow;
}
void main() {
    s1,s2,s3,s4;//原源点、原汇点,差网络新源点、新汇点
    s=s2,t=t2;
    rep(i,1,m) {//建边
        out[u]+=l,in[v]+=l;
        addedge(u,v,r-l);
    }
    rep(i,1,n) {//平衡下界网络的流量
        if(in[i]>out[i]) addedge(s,i,in[i]-out[i]), sum+=in[i]-out[i];
        else if(out[i]>in[i]) addedge(i,t,out[i]-in[i]);
    }
    addedge(t1,s1,inf);
    if(dinic()!=sum) {
        puts("There is no kexing flow!");
        exit(0);
    }
    int ans=e[cnt].f;
    e[cnt].f=e[cnt^1].f=0;
    s=s1,t=t1;
    ans+=dinic();
    pf("%d\n",ans);
}

其他

cdq 分治

namespace cdq {
    constexpr int N=1e5+7;
    int n,k;
    int f[N];
    struct node {
        int id,a,b,c,num,ans;
        bool operator < (const node &x) const {
            if(a==x.a) {
                if(b==x.b) return c < x.c; 
                else return b < x.b; 
            } else return a < x.a; 
        } 
    }x[N],t[N];
    int cnt;
    bool cmpb(node x,node y) { return x.b < y.b; }
    int tr[N<<1];
    void change(int x,int val) {
        for(;x<=k;x+=x&-x) tr[x]+=val;
    }
    int query(int x) {
        int s=0;
        for(;x;x-=x&-x) s+=tr[x];
        return s;
    }
    void solve(int l,int r) {
        if(l+1==r) return;
        int mid=(l+r)>>1;
        solve(l,mid), solve(mid,r);
        int p=l;
        rep(it,mid,r-1) {
            while(p<mid && x[p].b<=x[it].b) {
                change(x[p].c,x[p].num);
                ++p;
            }
            x[it].ans+=query(x[it].c);
        }
        rep(i,l,p-1) {
            change(x[i].c,-x[i].num);
        }
        int c=l;
        int itl=l,itr=mid;
        while(itl<mid && itr<r) {
            if(x[itl].b < x[itr].b) t[c++]=x[itl], ++itl;
            else t[c++]=x[itr], ++itr;
        }
        while(itl<mid) t[c++]=x[itl], ++itl;
        while(itr<r) t[c++]=x[itr], ++itr;
        memcpy(x+l,t+l,sizeof(node)*(r-l));
    }
    void main() {
        sf("%d%d",&n,&k);
        rep(i,1,n) {
            x[i].id=i;
            sf("%d%d%d",&x[i].a,&x[i].b,&x[i].c);
        }
        sort(x+1,x+n+1);
        rep(i,1,n) {
            if(x[i].a!=x[i-1].a || x[i].b!=x[i-1].b || x[i].c!=x[i-1].c) {
                ++cnt;
                x[cnt]=x[i];
                x[cnt].num=1;
            }
            else x[cnt].num++;
        }
        solve(1,cnt+1);
        rep(i,1,cnt) {
            f[x[i].ans+x[i].num-1] += x[i].num;
        }
        rep(i,0,n-1) pf("%d\n",f[i]);
    }
}
posted @ 2024-11-26 17:06  wing_heart  阅读(37)  评论(0)    收藏  举报