模板库

不定期更新,以下部分模板和他人共同完成,已标明

目录

就是提醒你看一下目录。

珂朵莉树

template<typename Tp, typename comp = std::equal_to<Tp> >
/**
 * comp(a,b) to decide if they can be merged
 * std::equal_to<_Tp> comes from <functional> (stl_function.h)
 *
 */
  class Chtholly {
    public:
        class iterator;//declare iterator
    private:
        struct node {//nodes in the set
            const int l;
            mutable int r;
            mutable Tp val;
            node() = delete;//for safety
            node(int L) : l(L) { }//for convenience
            node(int L, int R, const Tp& V) : l(L), r(R), val(V) { }
            bool operator < (const node& y) const {//for set's comparison
                return l < y.l;
            }
        };
        std::set<node> st;
        typedef typename std::set<node>::iterator IT;
        int _size_n;
        iterator _begin_iterator, _end_iterator;

        IT split(int pos) {
            if (pos<1) return st.begin();//A programmer get into a bar...
            IT it(std::prev(st.upper_bound(pos)));
            if (it->r < pos) return st.end();//Another programmer get into the bar...
            if (it->l == pos) return it;
            int tmpr = it->r;
            it->r = pos - 1;
            return st.insert(node(pos, tmpr, it->val)).first;
        }

        IT merge(IT i) {
            IT l(i), r(i);//caution: [l,r)
            while (l != st.begin()
                && comp()(prev(l)->val, i->val)
                ) --l;
            while (r != st.end()
                && comp()(r->val, i->val)
                ) ++r;
            int tl(l->l), tr(prev(r)->r);
			Tp tv(i->val);
            if (tl>tr) return i;//
            st.erase(l, r);
            return st.insert(node(tl, tr, tv)).first;
        }

        void merge(IT l, IT r) {//[l,r]
            int ed(r->r);
            while (l->r < ed) l=next(merge(l));
        }

        void merge()
        { merge(st.begin(), --st.end()); }

    public:
        Chtholly()//an empty sequence
        : st(), _size_n(0),
            _begin_iterator(1, st.begin()), _end_iterator(_size_n+1, st.end())
        { }

        Chtholly(int n, const Tp& val)
        : st(), _size_n(n)
        {
            st.insert(node(1, n, val));
            _begin_iterator = iterator(1, st.begin());
            _end_iterator = iterator(_size_n+1, st.end());
        }

        template<typename FI>
          Chtholly(FI first, FI end)//copy value from [first,end)
          : st(), _size_n(0)
        {
            if (first == end) return;
            Tp val(*first++);
            int l(1), r(1);
            while (first != end) {
                if ( !comp()(*first, val) ) {
                    ++_size_n;
                    st.insert(node(l, r, val));
                    val = *first;
                    l = r + 1;
                }
                ++first, ++r;
            }
            ++_size_n;
            st.insert(node(l, r, val));

            _begin_iterator = iterator(1, st.begin());
            _end_iterator = iterator(_size_n+1, st.end());
        }

        void clear()
        { st.clear(); }

        void rebuild()
        { *this = Chtholly(); }

        void rebuild(int n, const Tp& val)
        { *this = Chtholly(n, val); }

        template<typename FI>
          void rebuild(FI first, FI end)
        { *this = Chtholly(first, end); }

        void assign(int l, int r, const Tp& val) {//force to remake [l,r] val
            if (l>r) return;
            IT itr(split(r+1)), itl(split(l));
            st.erase(itl, itr);
            IT i = st.insert(node(l, r, val)).first;
            merge(i);
        }

        template<typename Rtn, typename... ArgList>
          void modify(int l , int r, Rtn (*func)(iterator, ArgList...), ArgList... arg) {
            if (l>r) return;//The third programmer ask for a bunch of noodles...
            IT itr(split(r+1)), itl(split(l));
            for (IT it(itl); it!=itr; ++it) {
                func(iterator(it->l, it), arg...);
            }
            merge(itl, itr);
        }

        template<typename FI>//copy [l,r] to 'destin'
          void copy_to(FI destin, int l, int r) const {
            IT it(--st.upper_bound(l));
            while (it != st.end()) {
                int lim(min(it->r, r));
                while (l <= lim) *destin++=it->val, ++l;
                if (l>r) return;
                ++it;
            }
        }

        const Tp operator [] (const int pos) const//you shound not change its value
        { return std::prev(st.upper_bound(pos))->val; }
        //O(log n)

        int size() const//length of the real array
        { return _size_n; }

        iterator begin() const
        { return _begin_iterator; }

        iterator end() const
        { return _end_iterator; }

        int bsize() const
        { return st.size(); }

        class iterator {
            private:
                int pos;//iterator in the real array
                IT it;//iterator in set
            public:
                iterator() = default;//for safety

                iterator(int ind, const IT& i)
                : pos(ind), it(i) { }

                iterator operator ++ () {
                    if (++pos > it->r) ++it;
                    return *this;
                }
                iterator operator ++ (int) {
                    iterator tmp = *this;
                    if (++pos > it->r) ++it;
                    return tmp;
                }
                iterator operator -- () {
                    if (--pos < it->l) --it;
                    return *this;
                }
                iterator operator -- (int) {
                    iterator tmp = *this;
                    if (--pos < it->l) --it;
                    return tmp;
                }
                bool operator == (const iterator& _x) const { return pos == _x.pos; }
                bool operator != (const iterator& _x) const { return pos != _x.pos; }
                bool operator <  (const iterator& _x) const { return pos <  _x.pos; }
                bool operator >  (const iterator& _x) const { return pos >  _x.pos; }
                bool operator <= (const iterator& _x) const { return pos <= _x.pos; }
                bool operator >= (const iterator& _x) const { return pos >= _x.pos; }

                Tp& operator * () { return it->val; }
                const int left() const { return it->l; }
                const int right() const { return it->r; }
                iterator prev() const { return iterator(it->l - 1, std::prev(it)); }
                iterator next() const { return iterator(it->r + 1, std::next(it)); }
        };
};

from Gyan(stO 封装の神 Orz)
压行版见https://gyan083.blog.luogu.org/da-bao-yi-ge-ke-duo-li-post
食用指南:
定义时传入第1个参数表示珂朵莉树维护的信息的类型,第2个参数表示两个节点在何时需要被合并(可以不写,默认为两个节点信息完全相同)
初始化时不传参数默认为空,可以传大小和初始值(只能有一个),还可以从一个数组或stl容器中一一拷贝值(似乎要\(\Theta(n\log n)\),效率略低)
支持调用子类Chtholly::iterator来访问具体的节点信息:
left()/right()询问区间的左右边界
可以用++/--移动迭代器,也可以用prev(it)/next(it)访问与it相邻的迭代器
Chtholly树支持:
begin()/end()返回第一/最后的迭代器
rebuild(int,Tp&)第一个参数设置珂朵莉树维护的区间大小,第二个参数将这个区间赋初值(也可以写在构造函数里,但不常用)
bsize()查询当前树有多少个节点,size()查看当前维护区间的大小
[]支持随机访问一个节点所在的区间,越界则返回最后一个节点,复杂度是\(\Theta(\log bsize)\)
clear()可以清空树从来没有用过
modify()需要传入修改操作在原序列上在左右边界和修改规则对应的函数change(第一个参数必须是Chtholly::iterator,之后可以接任意长参数),之后写change需要的其他参数

Splay

template<typename _Tp,unsigned N=10,_Tp INF=_Tp(2147483647)>
class Splay
{
private:
	unsigned Root,node_cnt;
	struct Node
	{
		_Tp v;
		unsigned cnt,siz,fa,ch[2];
		Node()=default;
	};
	std::vector<Node> node;
	std::vector<unsigned> del_list;
	unsigned vir_alloc()//动态申请点 
	{
		if(!del_list.empty())
		{
			unsigned tmp=del_list.back();
			del_list.pop_back();
			return tmp;
		}
		++node_cnt;
		if(node_cnt>=node.size())
		{
			if(node_cnt==node.capacity()) node.reserve(node.capacity()+15);
			node.emplace_back(Node());
		}
		return node_cnt;
	}
	void update(unsigned x)//更新
	{
		node[x].siz=node[node[x].ch[0]].siz+node[node[x].ch[1]].siz+node[x].cnt;
	}
	void rotate(unsigned x)//旋转
	{
		unsigned y=node[x].fa,z=node[y].fa,k=(node[y].ch[1]==x);
		node[z].ch[node[z].ch[1]==y]=x;
		node[x].fa=z;
		node[y].ch[k]=node[x].ch[k^1];
		node[node[x].ch[k^1]].fa=y;
		node[x].ch[k^1]=y;
		node[y].fa=x;
		update(y),update(x);
	}
	void splay(unsigned x,unsigned target=0)//转到目标节点的儿子
	{
		while(node[x].fa!=target)
		{
			unsigned y=node[x].fa,z=node[y].fa;
			if(z!=target)
				((node[z].ch[0]==y)^(node[y].ch[0]==x))?rotate(x):rotate(y);
			rotate(x);
		}
		if(!target)Root=x;
	}
	void find(_Tp x)//对应值节点转到根
	{
		unsigned cur=Root;
		if(!cur)return;
		while(node[cur].ch[x>node[cur].v]&&x!=node[cur].v)
			cur=node[cur].ch[x>node[cur].v];
		splay(cur);
	}
	unsigned find_pre_id(_Tp x)//查前驱编号 
	{
		find(x);
		if(node[Root].v<x)return Root;
		unsigned cur=node[Root].ch[0];
		while(node[cur].ch[1]) cur=node[cur].ch[1];
		splay(cur);
		return cur;
	}
	unsigned find_nxt_id(_Tp x)//查后继编号 
	{
		find(x);
		if(node[Root].v>x)return Root;
		unsigned cur=node[Root].ch[1];
		while(node[cur].ch[0]) cur=node[cur].ch[0];
		splay(cur);
		return cur;
	}
public:
	Splay()//初始化
	{
		Root=node_cnt=0;
		node.resize(N);
		node[0].siz=0,node[0].cnt=0,node[0].fa=0;
		insert(INF),insert(-INF);
	}
	void insert(_Tp x)//插入
	{
		unsigned cur=Root,from=0;
		while(cur&&x!=node[cur].v)
			from=cur,cur=node[cur].ch[x>node[cur].v];
		if(cur)
			++node[cur].cnt;
		else
		{
			cur=vir_alloc();
			if(!from) Root=cur;
			else node[from].ch[x>node[from].v]=cur;
			node[cur].v=x;
			node[cur].cnt=1;
			node[cur].fa=from;
			node[cur].siz=1;
			node[cur].ch[0]=node[cur].ch[1]=0;
		}
		splay(cur);
	}
	_Tp get_pre(_Tp x)//查前驱值 
	{
		return node[find_pre_id(x)].v;
	}
	_Tp get_nxt(_Tp x)//查后继值 
	{
		return node[find_nxt_id(x)].v;
	}
	bool erase(_Tp x)//删除 
	{
		unsigned x_pre=find_pre_id(x),x_nxt=find_nxt_id(x);
		splay(x_pre);
		splay(x_nxt,x_pre);
		unsigned cur=node[x_nxt].ch[0];
		if(!cur)return 0;
		if(node[cur].cnt>1)
		{
			--node[cur].cnt;
			splay(cur);
		}
		else del_list.emplace_back(node[x_nxt].ch[0]),node[x_nxt].ch[0]=0;
		return 1;
	}
	_Tp get_kth(unsigned rank)//找排名为k的
	{
		++rank;
		unsigned cur=Root,son;
		if(node[cur].siz<rank) return INF;
		while(1)
		{
			son=node[cur].ch[0];
			if(rank>node[son].siz+node[cur].cnt)
			{
				rank-=node[son].siz+node[cur].cnt;
				cur=node[cur].ch[1];
			}
			else if(node[son].siz>=rank) cur=son;
			else return splay(cur),node[cur].v;
		}
	}
	unsigned get_rank(_Tp x)//查排名
	{
		find(x);
		if(node[Root].v>=x) return node[node[Root].ch[0]].siz;
		return node[node[Root].ch[0]].siz+node[Root].cnt;
	}
	void reserve(unsigned cap)//直接申请更大空间 
	{
		if(node.capacity()<cap) node.reserve(cap);
		if(del_list.capacity()<(cap>>1)) del_list.reserve(cap>>1);
	}
};

from 人形魔芋
具体的食用指南可以在https://www.cnblogs.com/cmy-blog/p/splay.html 上看
使用了动态开点,效率较低,如果不是树套树等大小不定的场合,建议设定初始大小

LCT

class Data
{
	public:
		Data()=default;
};
template<int N=114514>
class LCT
{
	public: Data d[maxn];
	private:
		class node
		{
			public:
				bool rev;
				int c[2],fa;
				node()=default;
		};
		node s[N];
#define fa(x) s[x].fa
#define lc(x) s[x].c[0]
#define rc(x) s[x].c[1]
#define sonTp(x,fa) (s[fa].c[1]==x)
		inline void pushup(int x)
		{x--;}
		inline void access_pushup(int x,int y)
		{x&=y;}
		inline void cut_pushup(int x,int y)
		{x&=y;}
		inline void link_pushup(int x,int y)
		{x&=y;}
		inline bool nroot(int x) {return s[fa(x)].c[0]==x||s[fa(x)].c[1]==x;}
		inline void rev(int x)
		{
			if(!x) return;
			swap(lc(x),rc(x)),s[x].rev^=1;
			pushup(x);
		}
		inline void pushdown(int x)
		{
			if(s[x].rev)
				rev(lc(x)),
				rev(rc(x)),
				s[x].rev=0;
		}//记得这里也是要改的 
		inline void push_all(int x)
		{
			if(nroot(x)) push_all(fa(x));
			pushdown(x);
		}
		inline void rotate(int x)
		{
			int y=fa(x),z=fa(y),k=sonTp(x,y),w=s[x].c[!k];
			if(nroot(y)) s[z].c[sonTp(y,z)]=x;
			s[x].c[!k]=y;
			s[y].c[ k]=w;
			if(w) fa(w)=y;
			fa(x)=z,fa(y)=x;
			pushup(y);
			pushup(x);
		}
		inline void splay(int x)
		{
			static int y,z;
			push_all(x);
			while(nroot(x))
			{
				y=fa(x),z=fa(y);
				if(nroot(y)) rotate(sonTp(x,y)!=sonTp(y,z)?x:y);
				rotate(x);
			}
			pushup(x);
		}
	public:
		inline void access(int x)
		{
			for(int y=0;x;x=fa(y=x))
				splay(x),
				access_pushup(x,y),
				rc(x)=y,
				pushup(x);
		}
	private:
		inline void softRoot(int x)
		{
			access(x),
			splay(x);
		}
		inline int findRoot(int x)
		{
			softRoot(x);
			for(;lc(x);pushdown(x),x=lc(x));
			splay(x);
			return x;
		}
	public:
		inline bool sameRoot(int x,int y) {return findRoot(x)==findRoot(y);}
		inline void makeRoot(int x)
		{
			softRoot(x),
			rev(x);
		}
		inline void split(int x,int y)
		{
			makeRoot(x),
			softRoot(y);
		}
		inline bool edgeExist(int x,int y)
		{
			makeRoot(x);
			return findRoot(y)==x;
		}
		inline bool link(int x,int y)
		{
			if(edgeExist(x,y)) return false;
			softRoot(y);
			link_pushup(x,y);
			fa(x)=y;
			pushup(y);
			return true;
		}
		inline bool cut(int x,int y)
		{
			if(!edgeExist(x,y)) return false;
			softRoot(y);
			cut_pushup(x,y);
			lc(y)=fa(x)=0;
			pushup(x);
			return true;
		}
#undef fa
#undef lc
#undef rc
#undef sonTp
};

不得不说以前对于 LCT 的理解真是浅薄,实际上 LCT 有 \(4\)\(pushup\)

一种是已知节点儿子,更新节点信息,也就是第一个 \(pushup\)

第二种是在 \(access\) 过程中如果遇到虚实边的转化,需要进行虚实儿子的转化,就是 \(access\_pushup\)

第三种是 \(link\) 时会增加儿子,和虚实转化不太一样,还要有一个 \(link\_pushup\)

第四种是 \(cut\) 时,删除儿子,没有逆元的话就和 \(link\_pushup\) 不能混用

但实际写一下你就会发现几种 \(pushup\) 实际上很接近,但确实不一样

然后就是 $$

update 2021.10.28

update 2022.6.10 重写了

fhq-Treap

template<typename _Tp,_Tp maxVal,int N=1> 
class Treap
{
	private:
		void (*pushup)(_Tp&,_Tp&,_Tp&);
		const _Tp INF;
		mutable int Root,cnt;
		vector<int>del_list;
		class Node
		{
			public:
				mutable int ch[2],rnd,siz;
				mutable _Tp v;
				Node()=default;
		};
		vector<Node> node;
		inline void update(int x)
		{
			node[x].siz=node[node[x].ch[0]].siz+node[node[x].ch[1]].siz+1;
			if(pushup==NULL) return;
			pushup(node[x].v,node[node[x].ch[0]].v,node[node[x].ch[1]].v);
		}
		inline int newNode(int x)
		{
			static int tmp;
			if(del_list.empty())
			{
				if(++cnt>=node.size())
					node.emplace_back(Node());
				tmp=cnt;
			}
			else tmp=del_list.back(),del_list.pop_back();
			node[tmp].rnd=rand()*rand(),node[tmp].v=x,node[tmp].siz=1,node[tmp].ch[0]=node[tmp].ch[1]=0;
			return tmp;
		}
		inline void init()
		{
			node.resize(N);
			Root=cnt=0;
			insert(-INF),insert(INF);
		}
	public:
		inline void vsplit(int pos,_Tp v,int &x,int &y)
		{
			if(!pos)
			{
				x=y=0;
				return;
			}
			if(node[pos].v<=v) x=pos,vsplit(node[pos].ch[1],v,node[pos].ch[1],y);
			else y=pos,vsplit(node[pos].ch[0],v,x,node[pos].ch[0]);
			update(pos);
		}
		inline void ssplit(int pos,int k,int &x,int &y)
		{
			if(!pos)
			{
				x=y=0;
				return;
			}
			if(k>node[node[pos].ch[0]].siz)
				x=pos,ssplit(node[pos].ch[1],k-node[node[pos].ch[0]].siz-1,node[pos].ch[1],y);
			else y=pos,ssplit(node[pos].ch[0],k,x,node[pos].ch[0]);
			update(pos);
		}
		inline int merge(int x,int y)
		{
			if(!x||!y) return x+y;
			if(node[x].rnd<node[y].rnd)
			{
				node[x].ch[1]=merge(node[x].ch[1],y);
				update(x);
				return x;
			}
			node[y].ch[0]=merge(x,node[y].ch[0]);
			update(y);
			return y;
		}
		inline void insert(_Tp v)
		{
			int x,y;
			vsplit(Root,v,x,y);
			Root=merge(merge(x,newNode(v)),y);
		}
		inline void erase(_Tp& v)
		{
			int x,y,z;
			vsplit(Root,v,x,z);
			vsplit(x,v-1,x,y);
			del_list.push_back(y);
			y=merge(node[y].ch[0],node[y].ch[1]);
			Root=merge(merge(x,y),z);
		}
		inline _Tp pre(_Tp& v)
		{
			int x,y,cur;
			vsplit(Root,v-1,x,y);
			cur=x;
			while(node[cur].ch[1]) cur=node[cur].ch[1];
			merge(x,y);
			return node[cur].v;
		}
		inline _Tp nxt(_Tp& v)
		{
			int x,y,cur;
			vsplit(Root,v,x,y);
			cur=y;
			while(node[cur].ch[0]) cur=node[cur].ch[0];
			merge(x,y);
			return node[cur].v;
		}
		inline int get_rank(_Tp& v)
		{
			int x,y,ans;
			vsplit(Root,v-1,x,y);
			ans=node[x].siz;
			merge(x,y);
			return ans;
		}
		inline _Tp kth(int k)
		{
			++k;
			int x,y,cur;
			ssplit(Root,k,x,y);
			cur=x;
			while(node[cur].ch[1]) cur=node[cur].ch[1];
			merge(x,y);
			return node[cur].v;
		}
		inline _Tp operator [] (int k){return kth(k);}
		Treap():INF(maxVal)
		{
			pushup=NULL;
			init();
		}
		Treap(void(*change)(_Tp&,_Tp&,_Tp&)):INF(maxVal)
		{
			pushup=change;
			init();
		}
		Treap(_Tp* st,_Tp* ed):INF(maxVal)
		{
			pushup=NULL;
			init();
			while(st<ed) insert(*st++);
		}
		Treap(_Tp* st,_Tp* ed,void(*change)(_Tp&,_Tp&,_Tp&)):INF(maxVal)
		{
			pushup=change;
			init();
			while(st<ed) insert(*st++);
		}
};

再次感谢人形魔芋
支持[]访问(第k大),其他函数功能和splay相同,和LCT一样,需要在构造时加入上传规则(不写则默认为NULL,什么也不做)
定义时传入的参数含义从左往右依次为节点类型,无穷值(需重载负号),预设大小
构造函数有:
1.无参数,自动插入\(\pm INF\),上传规则为空
2.一个参数,表示一个带三个_Tp类型参数的void函数指针(具体同LCT),即上传规则
3.两个参数,表示将一段连续内存作为初始值
4.三个参数,前两个参数表示一段连续内存做初始值,第三个参数表示上传规则

线段树

在这里
upd 2022.4.9

取模意义下的int

namespace ModInt
{
	static int mod=998244353;
	static vector<int> Inv;
class mint
{
	private:
		int num;
	public:
		inline void show() {write_(num);}
		~mint()=default;
		mint()=default;
		mint(int x,int y):num(mint(x)/mint(y)){}
		mint(int x):num(x){if(num<0) num%=mod,num+=mod;if(num>=mod) num%=mod;}
		mint operator + (const mint& a){int c=a.num+num;return mint(c>=mod?c-mod:c);}
		friend mint operator - (const mint& a,const mint& b){int c=a.num-b.num;return mint(c<0?c+mod:c);}
		friend mint operator * (const mint& a,const mint& b){ll c=(ll)a.num*b.num;return mint(c>=mod?c%mod:c);}
		friend mint operator / (const mint& a,const mint& b){if(Inv.size()<(unsigned)(b.num+2))return a*inv(b);return a*Inv[b.num];}
		friend mint operator / (int a,mint b){return mint(a)/b;}
		friend mint operator / (mint a,int b){return a/mint(b);}
		void operator +=(const mint& x){int c=x.num+num;num=c>=mod?c-mod:c;}
		void operator -=(const mint& x){int c=num-x.num;num=c<0?c+mod:c;}
		int operator &(const int &x){return x&num;}
		mint operator &(const mint &x){return mint(x.num&num);}
		friend int operator &(const int& x,const mint &y){return x&(y.num);}
		int operator |(const int &x){return x|num;}
		mint operator |(const mint &x){return mint(x.num|num);}
		friend int operator |(const int& x,const mint &y){return x|(y.num);}
		int operator ^(const int &x){return x^num;}
		mint operator ^(const mint &x){return mint(x.num^num);}
		friend int operator ^(const int& x,const mint &y){return x^(y.num);}
		mint operator >> (const int& x) {return mint(num>>=x);} 
		void operator >>=(const int& x) {num>>=x;} 
		mint operator << (int x)
		{
			static int tw,d;
			static ll tmp;
			tw=2,d=1;
			while(x) (x&1)&&(tmp=(ll)d*tw,d=(tmp>=mod?tmp%mod:tmp),1),tmp=(ll)tw*tw,tw=(tmp>=mod?tmp%mod:tmp),x>>=1;
			tmp=(ll)num*d,tmp=(tmp>=mod?tmp%mod:tmp);
			return mint(tmp);
		}
		friend void operator <<=(mint x,int y){x.num=x<<y;}
		friend mint operator << (mint x,mint y){return x<<(int)y;}
		friend mint operator << (int x,mint y){return mint(x)<<(int)y;}
		friend mint pow(mint d,mint x);
		friend mint inv(mint a){return pow(a,mint(mod-2));}
		mint operator - () {mint m(-num);return m;}
		mint operator ++ (int) {++num;return *this;}
		mint operator ++ () {mint c(num);return ++num,c;}
		mint operator -- (int) {--num;return *this;}
		mint operator -- () {mint c(num);return --num,*this;}
		friend mint operator + (mint x,int y) {int q=x.num+y;q=q>=mod?q-mod:q;return mint(q);}
		friend mint operator - (mint x,int y) {int q=x.num-y;q=q<0?q+mod:q;return mint(q);}
		operator int(){return num;}
		friend mint operator * (mint x,int y) {return x*mint(y);}
		friend mint operator * (int x,mint y) {return mint(x)*y;}
		void operator *= (const mint x){ll l=(ll)x.num*num;num=l>=mod?l%mod:l;}
		void operator *= (const int x){ll l=(ll)num*x;num=(l>=mod?(l>=(mod<<1)?l%mod:l-mod):l);}
		void operator += (int x){num+=x,num=num>=mod?num-mod:num;}
		void operator -= (int x){num-=x;num=num<0?num+mod:num;}
		void operator /= (mint b){num=num/b.num;}
		bool operator!(){return !num;}
		friend ostream &operator<<(ostream &out , const mint &a){out<<a.num;return out;}
};
inline void read_(mint &x)
{
	int fi=1;x=0;
	char op=getchar();
	while((op<'0'||op>'9')&&op!='-') op=getchar();
	if(op=='-') op=getchar(),fi=-1;
	while(op>='0'&&op<='9') x=x*10+(op^48),op=getchar();
	x=x*mint(fi);
	return;
}
inline mint pow(mint d,mint x){mint as=1;while(x)as=(x&1?as*d:as),d=d*d,x>>=1;return as;}
inline void InvInit(unsigned int n)
{
	if(Inv.size()>n) return;
	if(n>Inv.max_size()) {assert("Too much number!");return;}
	unsigned int tmp=Inv.size()-1;
	Inv.resize(n+4,0);
	if(tmp<1) Inv[1]=1;
	for(unsigned int i=max(2u,tmp);i<=n;++i) Inv[i]=(ll)Inv[mod%i]*(mod-mod/i)%mod;
}
};
using ModInt::mint;

使用时修改mod的值即可,其它使用和int没有区别,支持cout,不支持cin,scanf,printf(太慢),手写了一个读入函数\(read_()\),个人比较喜欢引用版(不会有人不会改快读吧)
大概可以避免手写一串函数嵌套做多项式运算~
update2021.11.10:温馨提醒,常数巨大,大概是2倍,因为没有懒取模的优化,虽然用-优化了\(\pm\),但还是很慢,不过使用\(+=,-=,*=\)可以较为显著的缩小常数(构造函数里面有判断),不过O2神力之后和正常的就没有区别了,但用位运算变成了最慢的运算之一
update:2021.11.12 可以使用mint做下标了,增加了线筛逆元优化除法(可能会反复用)

2-SAT板子

namespace two_sat
{
	#define two_sat_size 2000005
int n;
int tot,nex[two_sat_size<<2],to[two_sat_size<<2],head[two_sat_size];
inline void add(int u,int v){nex[++tot]=head[u],to[head[u]=tot]=v;}
int fa[two_sat_size],top_mark[two_sat_size],cnt,dep[two_sat_size];
inline int find_fa(int x){return x==fa[x]?x:fa[x]=find_fa(fa[x]);}
inline void dfs(int now)
{
	for(int i=head[now],v=to[i];i;v=to[i=nex[i]])
	{
		if(!dep[v]) dep[v]=dep[now]+1,dfs(v);
		if(dep[find_fa(v)]>0)
		{
			if(dep[find_fa(now)]<dep[fa[v]]) fa[fa[v]]=fa[now];
			else fa[fa[now]]=fa[v];
		}
	}
	dep[now]=-1,top_mark[now]=++cnt;
}
inline void solve()
{
	for(int i=1;i<=n<<1;++i) fa[i]=i,dep[i]=0;//init
	for(int i=1;i<=n<<1;++i)
		if(!dep[i])
			dfs(i);
}
inline bool possible()
{
	for(int i=1;i<=n;++i) if(find_fa(i)==find_fa(i+n)) return false;
	return true;
}
inline bool is_true(int x){return top_mark[x]<top_mark[x+n];}
inline void add(int x,int a,int y,int b)
{
	if(x==y&&a!=b) return;
	add(x+(a&1?n:0),y+(b^1?n:0)),
	add(y+(b&1?n:0),x+(a^1?n:0));
}
inline void not_equal(int x,int y) {add(x,0,y,0),add(x,1,y,1);}
	#undef two_sat_size
};

update 2021.11.18 自己写了2-SAT的一些题,发现很多都是板子,重复地打很麻烦,于是封装了一个板子
\(possible\,\)表示是否有解,\(is\_true\,\)返回一个变量的取值(事实上,这可能是不唯一的),\(solve\,\)将重新计算答案(\(\Theta(n+m)\)
\(not_equal\,\)选定两个变量值不同
\(add\,\)有四个参数,依次记为\(\,x,a,y,b\),表示\(\,x=a\ \vee\ y=b\,\),不能删边,想不到很好的实现方法

AC自动机

template<int N,int son_size=26>
class AC_machine
{
	private:
		class Node
		{
			public:
				int end;
				int end_id;
				int fail;
				int son[son_size];
				int g_fail;
				Node()=default;
		}node[N];
		int cnt;
		static inline int turn(char ch){return ch-'a';}
		int vir_alloc(){return ++cnt;}
		int (*make_id)(char);
	public:
		AC_machine():make_id(turn){}
		AC_machine(int (*change)(char)):make_id(change){}
		int size(){return cnt;}
		void insert(string s,int id=0)
		{
			int l=s.size(),now=0,tmp=0;
			for(int i=0;i<l;++i)
				if(!node[now].son[tmp=make_id(s[i])]) now=node[now].son[tmp]=vir_alloc();
				else now=node[now].son[make_id(s[i])];
			++node[now].end,node[now].end_id=id;
		}
		void build()
		{
			static queue<int> q;
			node[0].fail=0;
			for(int i=0;i<son_size;++i)
				if(node[0].son[i])
					node[node[0].son[i]].fail=0,
					q.push(node[0].son[i]);
			int now;
			while(!q.empty())
			{
				now=q.front(),q.pop();
				for(int i=0;i<son_size;++i)
					if(node[now].son[i])
					{
						node[node[now].son[i]].fail=node[node[now].fail].son[i];
						if(node[node[node[now].son[i]].fail].end) node[node[now].son[i]].g_fail=node[node[now].son[i]].fail;
						else node[node[now].son[i]].g_fail=node[node[node[now].son[i]].fail].g_fail;
						q.push(node[now].son[i]);
					}
					else
						node[now].son[i]=node[node[now].fail].son[i];
			}
		}
		int count(string s)//不重复
		{
			static bitset<N> vis;
			vis.reset();
			int len=s.size(),now=0,ans=0;
			for(int i=0;i<len;++i)
			{
				now=node[now].son[make_id(s[i])];
				for(int t=now;t&&!vis[t];t=node[t].g_fail)
					ans+=node[t].end,
					vis[t]=1;
			}
			return ans;
		}
		void clear()
		{
			for(int i=0;i<=cnt;++i)
				memset(node[i].son,0,sizeof node[i].son),
				node[i].g_fail=node[i].fail=node[i].end=0;
			cnt=0;
		}
};

两个模板参数,表示自动机的大小和trie的叉数(可选),构造时默认字符都是小写字母,可以自己写其他从char到int的映射写到构造函数里,好像只能统计出现次数~

SGLT

一种 \(WBLT\),但是不能旋转,有点拉

namespace SGLT
{
	const double alpha=0.72;//平衡因子
	bool fail;
	class node
	{
	public:
		int c[2];//儿子
		int siz,cnt;//树结构上的大小,键值数
		int val;//子树最大值
		node()=default;
	}; node s[maxn<<3]; int cnt;
	vector<int> del_list;
	inline int vir_alloc()
	{
		if(!del_list.empty()) { int tp=del_list.back(); del_list.pop_back(); return tp; }
		return ++cnt;
	}//申请新节点
#define ls(x) s[x].c[0]
#define rs(x) s[x].c[1]
#define leaf(x) (!s[x].c[0]&&!s[x].c[1])
	inline bool bal(int x)//判断是否平衡
	{ return min(s[ls(x)].siz,s[rs(x)].siz)==0||max(s[ls(x)].siz,s[rs(x)].siz)<=s[x].siz*alpha; }
	inline void pushup(int x)
	{
		if(leaf(x)) return;
		s[x].siz=s[x].cnt=0,s[x].val=-inf;
		if(ls(x))
		{
			if(s[ls(x)].cnt==0) del_list.emplace_back(ls(x)),s[ls(x)]=node(),ls(x)=0;
			else
			{
				chkmax(s[x].val,s[ls(x)].val);
				s[x].siz+=s[ls(x)].siz,s[x].cnt+=s[ls(x)].cnt;
			}
		}//有时左右节点需要不同的处理,所以分开了
		if(rs(x))
		{
			if(s[rs(x)].cnt==0) del_list.emplace_back(rs(x)),s[rs(x)]=node(),rs(x)=0;
			else
			{
				chkmax(s[x].val,s[rs(x)].val);
				s[x].siz+=s[rs(x)].siz,s[x].cnt+=s[rs(x)].cnt;
			}
		}
	}//更新节点信息
	
	vector<int> flat;//拍扁数组,stl重度依赖
	inline void rebuild_dfs(int x)
	{
		if(leaf(x)) { flat.emplace_back(x); return; }
		if(ls(x)) rebuild_dfs(ls(x));
		if(rs(x)) rebuild_dfs(rs(x));
		del_list.emplace_back(x),s[x]=node();
	}//拍扁
	inline int lift(int l,int r)
	{
		if(r<l) return 0;
		if(l==r) return flat.at(l);
		int mid=(l+r)>>1,p=vir_alloc();
		s[p].c[0]=lift(l,mid);
		s[p].c[1]=lift(mid+1,r);
		pushup(p);
		return p;
	}//提起
	inline int rebuild(int x)
	{
		if(!flat.empty()) flat.clear();//如果shrink了会很慢
		rebuild_dfs(x);
		x=lift(0,flat.size()-1);
		return x;
	}//重构
	inline bool insert(int &x,int v)
	{
		if(!x) { x=vir_alloc(),s[x].siz=s[x].cnt=1,s[x].val=v; return 0; }
		if(leaf(x))
		{
			//		debug_out("leafy");
			if(s[x].val==v) { ++s[x].cnt; return 0; }
			int p=vir_alloc(),k=s[x].val>v;
			s[x].c[k]=p;
			s[p].siz=1,s[p].cnt=s[x].cnt,s[p].val=s[x].val;
			s[x].c[k^1]=p=vir_alloc();
			s[p].siz=1,s[p].cnt=1,s[p].val=v;
			pushup(x);
			return 0;
		} bool t=0,k=0;
		if(!ls(x)||s[ls(x)].val<v) t=insert(rs(x),v),k=1;
		else t=insert(ls(x),v),k=0;
		pushup(x);
		if(!bal(x)) return 1;
		if(t)
		{
			s[x].c[k]=rebuild(s[x].c[k]);
			pushup(x);
		} return 0;
	}
	inline void erase(int x,int v)
	{
		if(!x) return;
		if(leaf(x))
		{
			if(s[x].val!=v) { fail=1; return; }
			if(--s[x].cnt==0) s[x].siz=0,fail=0;
			return;
		}
		if(!ls(x)||s[ls(x)].val<v) erase(rs(x),v);
		else erase(ls(x),v);
		pushup(x);
		return;
	}
	inline int kth(int x,int k)
	{
		if(!x||s[x].cnt<k) return -inf;
		if(leaf(x)) return s[x].val;
		if(!ls(x)||s[ls(x)].cnt<k) return kth(rs(x),k-s[ls(x)].cnt);
		return kth(ls(x),k);
	}
	inline int sum(int x,int v)
	{
		if(!x) return 0;
		if(leaf(x))
		{
			if(s[x].val<=v) return s[x].cnt;
			return 0;
		}
		if(!ls(x)||s[ls(x)].val<v) return s[ls(x)].cnt+sum(rs(x),v);
		return sum(ls(x),v);
	}
	inline int rnk(int x,int v) { return sum(x,v-1)+1; }
	inline int pre(int x,int v) { return kth(x,sum(x,v-1)); }
	inline int nxt(int x,int v) { return kth(x,sum(x,v)+1); }
	
	class scapeGoatTree
	{
	private:
		int rt;
		inline void shrink(int x)
		{
			if(ls(x)) shrink(ls(x));
			if(rs(x)) shrink(rs(x));
			del_list.emplace_back(x),s[x]=node();
		}
	public:
		inline void insert(int v) { if(SGLT::insert(rt,v)) rt=SGLT::rebuild(rt); }
		inline bool erase(int v) { SGLT::erase(rt,v); return fail; }//删除不需要重构,返回是否删除成功
		inline int kth(int k) { return SGLT::kth(rt,k); }
		inline int rnk(int v) { return SGLT::rnk(rt,v); }
		inline int pre(int v) { return SGLT::pre(rt,v); }
		inline int nxt(int v) { return SGLT::nxt(rt,v); }
		inline void clear() { rt=0; }//只是清除数据
		inline void shrink() { shrink(rt); }//清除数据和空间
		scapeGoatTree()=default;
	};
} SGLT::scapeGoatTree sgt;

DSU

不带按秩合并的版本,这样可以确定父亲的方向。

class DSU
{
private:
	int N;
	vector<int> fa;
public:
	inline void resize(int n)
	{
		N=n;
		fa.resize(n,-1);
		urep(i,0,n-1) fa[i]=-1;
	}
	inline void init(int n) { resize(n+1); }
	inline int find(int x) { return fa[x]==-1?x:fa[x]=find(fa[x]); }
	inline void merge(int x,int y)
	{
		x=find(x),y=find(y);
		if(x==y) return;
		fa[y]=x;
	}
	inline bool check(int x,int y) { return find(x)==find(y); }
	inline int size() { return N; }
	DSU()=default;
	DSU(int n) { init(n); }
};

按大小合并的版本,效率和按秩合并差不多,就不写按秩合并了。

class DSU
{
private:
	int N;
	vector<int> fa,siz;
public:
	inline void resize(int n)
	{
		N=n;
		fa.resize(n,-1);
		siz.resize(n,1);
		urep(i,0,n-1) fa[i]=-1,siz[i]=1;
	}
	inline void init(int n) { resize(n+1); }
	inline int find(int x) { return fa[x]==-1?x:fa[x]=find(fa[x]); }
	inline void merge(int x,int y)
	{
		x=find(x),y=find(y);
		if(x==y) return;
		if(siz[x]<siz[y]) swap(x,y);
		siz[x]+=y,fa[y]=x;
	}
	inline bool check(int x,int y) { return find(x)==find(y); }
	inline int size(int x) { return siz[find(x)]; }
	inline int size() { return N; }
	DSU()=default;
	DSU(int n) { init(n); }
};

带花树

依赖DSU,必须使用第一个DSU,即不启发式合并的版本,不然会错。

class blossomy_tree
{
private:
	int n;
	DSU s;
	queue<int> q;
	int dfncnt;
	veci* e;
	int *match,*pre,*col,*dfn;
	inline int lca(int x,int y)
	{
		++dfncnt;
		x=s.find(x),y=s.find(y);
		while(dfn[x]!=dfncnt)
		{
			dfn[x]=dfncnt;
			x=s.find(pre[match[x]]);
			if(y) swap(x,y);
		} return x;
	}
	inline void blossom(int x,int y,int w)
	{
		while(s.find(x)!=w)
		{
			pre[x]=y;
			y=match[x];
			if(col[y]==2) col[y]=1,q.push(y);
			if(s.find(x)==x) s.merge(w,x);
			if(s.find(y)==y) s.merge(w,y);
			x=pre[y];
		}
	}
	inline bool getMatch(int x)
	{
		irep(i,1,n) col[i]=pre[i]=0;
		s.init(n);
		q=queue<int>();
		while(!q.empty()) q.pop();
		q.push(x);
		col[x]=1;
		while(!q.empty())
		{
			x=q.front(),q.pop();
			for(int y:e[x])
			{
				if(s.check(x,y)||col[y]==2) continue;
				if(!col[y])
				{
					col[y]=2;
					pre[y]=x;
					if(!match[y])
					{
						for(int k=y,p;k;k=p)
							p=match[pre[k]],
							match[k]=pre[k],
							match[pre[k]]=k;
						return 1;
					}
					col[match[y]]=1;
					q.push(match[y]);
				}
				else
				{
					int w=lca(x,y);
					blossom(x,y,w);
					blossom(y,x,w);
				}
			}
		}
		return 0;
	}
public:
	inline int getAns(int N)
	{
		n=N;
		dfncnt=0;
		int r=0;
		irep(i,1,n) if(!match[i]) r+=getMatch(i);
		return r;
	}
	blossomy_tree()=default;
	blossomy_tree(veci* e,int *match,int *pre,int *col,int *dfn):
		e(e),match(match),pre(pre),col(col),dfn(dfn)
	{ }
};

传入需要用到的数组,这样封装的算法类自己几乎不占用空间,而且不影响使用,同时还兼顾了开放性,使得输出过程变的容易。

代数环

template<typename numberType>
class circle_system
{
private:
	using T=numberType;
	using operation=T(*)(T,T);
	using single_operation=T(*)(T);
public:
	T zero,one;
	operation add,mul;
	single_operation op;
	inline T sub(T a,T b) { return add(a,op(b)); }
	inline void Add(T&a,T b) { a=add(a,b); }
	inline void Sub(T&a,T b) { a=sub(a,b); }
	inline void Mul(T&a,T b) { a=mul(a,b); }
	circle_system() { }
	circle_system(operation a,operation m=0,single_operation o=0):
		add(a),mul(m),op(o)
	{ }
	circle_system(T zero,T one,operation a,operation m=0,single_operation o=0):
		zero(zero),one(one),add(a),mul(m),op(o)
	{ }
	inline T pow(T a,int t)
	{
		T r=one;
		while(t)
		{
			if(t&1) r=mul(r,a);
			a=mul(a,a),t>>=1;
		} return r;
	}
};

字符串哈希

namespace myHash
{
	struct hashNode {
		u32 x,y;
		hashNode()=default;
		hashNode(u32 _x,u32 _y):x(_x),y(_y) { }
		friend bool operator ==(hashNode a,hashNode b) { return a.x==b.x&&a.y==b.y; }
		friend bool operator !=(hashNode a,hashNode b) { return a.x!=b.x||a.y!=b.y; }
		friend ostream & operator << (ostream& os,hashNode& hs) {
			os<<'('<<hs.x<<','<<hs.y<<')';
			return os;
		}
		inline ull trans() { return ((ull)y<<32ull)|x; }
	}; hashNode hashMiss(-1,-1);
	const u32 hashModMv=time(0);
	class myHashStr
	{
	private:
		class fastmod
		{
		private:
			ull m;
			u32 l;
			inline void init()
			{
				if(!p) cerr<<("p is zero!\n");
				l=32u-__builtin_clz(p-1);
				ull low=(ull(1)<<(32u+l))/p;
				ull high=((1ull<<(32u+l))+(1ull<<l))/p;
				while( (low>>1)<(high>>1) && l>0 ) low>>=1,high>>=1,--l;
				m=high;
			}
			inline u32 mulhigh(u32 x,u32 y) { return ((ull)x*y)>>32ull; }
		public:
			u32 p;
			inline u32 div(u32 x)
			{
				if(m>UINT32_MAX)
				{
					u32 t=mulhigh(x,m-(1ull<<32ull));
					return (((x-t)>>1)+t)>>(l-1);
				} return mulhigh(x,m)>>l;
			} inline u32 mod(u32 x) { return x-p*div(x); }
			fastmod():p(998244353) { init(); }
			fastmod(u32 x):p(x) { init(); }
		};
		class safeFastmod
		{
		private:
			fastmod p;
			u32 err;
			bool al2;
			inline void init()
			{
				if(!err) cerr<<("p is zero!\n");
				al2=0;
				u32 r=0;
				while(!(err&1u)) err>>=1u,++r;
				if(err==1u)
				{
					err=r,al2=1;
					return;
				}
				p=fastmod(err);
				err=r;
			}
		public:
			inline u32 div(u32 x)
			{
				if(al2) return x>>err;
				return p.div(x>>err);
			}
			inline u32 mod(u32 x)
			{
				if(al2) return x&((1u<<err)-1u);
				return x-((div(x)*p.p)<<err);
			}
			inline u32 mod_num() { return al2?1u<<err:p.p<<err; }
			safeFastmod() { p=fastmod(998244353),err=1,al2=0; }
			safeFastmod(u32 p) { err=p; init(); }
		}; safeFastmod P,SQ;
		u32 B1,B2,sq,maxlen;
		vector<hashNode> hs;
		vector<u32> pb1,pb2,pb3,pb4;//
		inline u32 mul(u32 x,u32 y) { ull z=1ull*x*y; return z>=P.mod_num()?P.mod(z):z; }
		inline void init_power(u32 x)
		{
			if(maxlen==x) return;
			maxlen=x;
			sq=sqrt(x)+1;
			SQ=safeFastmod(sq);
			pb1.resize(sq+1); pb2.resize(sq+1);
			pb3.resize(sq+1); pb4.resize(sq+1);
			hs.resize(x+2);
			pb1[0]=1u; pb2[0]=1u;
			for(u32 i=1;i<=sq;++i)
				pb1[i]=mul(pb1[i-1],B1),
				pb2[i]=pb2[i-1]*B2;
			pb3[0]=1u; pb4[0]=1u;
			pb3[1]=mul(pb1[sq-1],B1);
			pb4[1]=pb2[sq-1]*B2;
			for(u32 i=2;i<=sq;++i)
				pb3[i]=mul(pb3[i-1],pb3[1]),
				pb4[i]=pb4[i-1]*pb4[1];
		}
		inline u32 qpow1(u32 t)
		{
			if(t<=maxlen) return mul(pb1[SQ.mod(t)],pb3[SQ.div(t)]);
			u32 r=1,a=B1;
			while(t) {
				if(t&1) r=mul(r,a);
				a=mul(a,a),t>>=1;
			} return r;
		}
		inline u32 qpow2(u32 t)
		{
			if(t<=maxlen) return pb2[SQ.mod(t)]*pb4[SQ.div(t)];
			u32 r=1,a=B2;
			while(t) {
				if(t&1) r*=a;
				a=a*a,t>>=1;
			} return r;
		}
	public:
		myHashStr()
		{
			maxlen=0,B1=114+(hashModMv>>3),B2=1919+(hashModMv>>4);
			B1|=1,B2|=1;
			u32 tmp=(u32)(hashModMv+998244353u);//a rand mod num
			if(tmp<100000000u) tmp=1e9+7;//the mod can't be too min
			P=safeFastmod(tmp);
			B1=P.mod(B1);
		}
		myHashStr(u32 b1,u32 b2,ull p) { maxlen=0,B1=b1,B2=b2,P=safeFastmod(p); B1=P.mod(B1); } 
		inline void build(string& s)
		{
			if(s.empty()) return;
			init_power(s.size());
			hs[0]=hashNode(s[0],s[0]);
			for(u32 i=1;i<s.size();++i)
			{
				hs[i].x=hs[i-1].x+mul(qpow1(i),s[i]);
				if(hs[i].x>=P.mod_num()) hs[i].x-=P.mod_num();
				hs[i].y=hs[i-1].y+s[i]*qpow2(i);
			}
		}
		inline hashNode getHash(u32 l,u32 r,u32 up_to)
		{
			if(l>r||l>up_to||r>maxlen) return hashMiss;
			if(l==0)
				return hashNode(mul(hs[r].x,qpow1(up_to)),hs[r].y*qpow2(up_to));
			hashNode tmp;
			if(hs[r].x>=hs[l-1].x) tmp.x=hs[r].x-hs[l-1].x;
			else tmp.x=P.mod_num()-hs[l-1].x+hs[r].x;
			tmp.y=hs[r].y-hs[l-1].y;
			tmp.x=mul(tmp.x,qpow1(up_to-l));
			tmp.y*=qpow2(up_to-l);
			return tmp;
		} inline hashNode getHash(u32 l,u32 r) { return getHash(l,r,maxlen); }
		//move it by some step so that it begins at [up_to]
		inline hashNode LinkHash(hashNode a,hashNode b,u32 lenA)
		{
			if(a.x>=P.mod_num()) a.x=P.mod(a.x);//init
			b.x=mul(b.x,qpow1(lenA));
			b.y*=qpow2(lenA);
			a.x+=b.x,a.y+=b.y;
			if(a.x>=P.mod_num()) a.x-=P.mod_num();
			return a;
		}//we believe you have make a and b at the asme begining
		inline void clear() { maxlen=0; }
		inline void destroy()
		{
			hs.clear(); hs.shrink_to_fit();
			pb1.clear(); pb1.shrink_to_fit();
			pb2.clear(); pb2.shrink_to_fit();
			pb3.clear(); pb3.shrink_to_fit();
			pb4.clear(); pb4.shrink_to_fit();
		}
		~myHashStr() { destroy(); }
	};
}

upd 2022.11.15

二维数点

template<typename coordType=int,typename valueType=int>
class static_planar_node_count
{
private:
	using T=coordType;
	using V=valueType;
	using planar_node=k_Node::node<2,T>;
	using planar_square=k_Node::node<4,T>;
	planar_node* p;
	planar_square* s;
	V *ans;
	bool haveWeight=0;
	V *val;
	int totx,toty;
	T *x,*y;
	class ex_square
	{
	public:
		int l,r;
		int column;
		int id;
		ex_square() { }
		ex_square(int l,int r,int c,int i):l(l),r(r),column(c),id(i) { }
		bool operator < (const ex_square&a) { return column<a.column; }
	}; vector<ex_square> del,ins;
	class insertNode
	{
	public:
		int col,pos;
		V v;
		insertNode()=default;
		insertNode(int c,int p,V v):col(c),pos(p),v(v) { }
		bool operator < (const insertNode& b) const { return col<b.col; }
	}; vector<insertNode> add;
	inline void discretize(int n,int m)
	{
		x=new T [n+2*m+2];
		y=new T [n+2*m+2];
		totx=toty=0;
		irep(i,1,n) x[++totx]=p[i][0],y[++toty]=p[i][1];
		irep(i,1,m) x[++totx]=s[i][0],x[++totx]=s[i][2],y[++toty]=s[i][1],y[++toty]=s[i][3];
		sort(x+1,x+totx+1);
		sort(y+1,y+toty+1);
		totx=unique(x+1,x+totx+1)-x-1;
		toty=unique(y+1,y+toty+1)-y-1;
		irep(i,1,n)
		{
			int now=lower_bound(x+1,x+totx+1,p[i][0])-x;
			int pos=lower_bound(y+1,y+toty+1,p[i][1])-y;
			if(haveWeight) add.emplace_back(insertNode(now,pos,val[i]));
			else add.emplace_back(insertNode(now,pos,1));
		}
		for(int i=1;i<=m;++i)
		{
			int l=lower_bound(y+1,y+toty+1,s[i][1])-y,r=lower_bound(y+1,y+toty+1,s[i][3])-y;
			int x1=lower_bound(x+1,x+totx+1,s[i][0])-x,x2=lower_bound(x+1,x+totx+1,s[i][2])-x;
			del.emplace_back(ex_square(l,r,x1,i));
			ins.emplace_back(ex_square(l,r,x2,i));
		}
		sort(add.begin(),add.end());
		sort(del.begin(),del.end());
		sort(ins.begin(),ins.end());
		delete[]x;
		delete[]y;
	}
	class BIT
	{
	private:
		inline int lowbit(int x) { return x&(-x); }
		vector<V> a;
		int N;
	public:
		inline void init(int n)
		{
			a.resize(n+1);
			irep(i,0,n) a[i]=0;
			N=n;
		}
		inline void add(int x,V k) { for(;x<=N;x+=lowbit(x)) a[x]+=k; }
		inline V sum(int x) { V r=0; for(;x>0;x-=lowbit(x)){r+=a[x];} return r; }
		inline V sum(int l,int r) { return sum(r)-sum(l-1); }
		inline void destroy() { a.clear(),a.shrink_to_fit(); }
	}; BIT bit;
public:
	static_planar_node_count() { }
	static_planar_node_count(planar_node*point,planar_square*square,V*as,bool Weighted=0,V*v=0):
		p(point),s(square),ans(as),haveWeight(Weighted),val(v)
	{
		totx=toty=0;
		x=y=nullptr;
	}	
	~static_planar_node_count()
	{
		bit.destroy();
		add.clear(),del.clear(),ins.clear();
		add.shrink_to_fit(),del.shrink_to_fit(),ins.shrink_to_fit();
	}
	inline void count(int n,int m)
	{
		discretize(n,m);
		bit.init(toty);
		unsigned delpos=0,addpos=0,inspos=0;
		int l,r,id,pos;
		V v;
		irep(i,1,totx)
		{
			while(delpos<del.size()&&del[delpos].column==i)
				l=del[delpos].l,r=del[delpos].r,id=del[delpos].id,
				ans[id]-=bit.sum(l,r),
				++delpos;
			while(addpos<add.size()&&add[addpos].col==i)
				pos=add[addpos].pos,v=add[addpos].v,
				bit.add(pos,v),
				++addpos;
			while(inspos<ins.size()&&ins[inspos].column==i)
				l=ins[inspos].l,r=ins[inspos].r,id=ins[inspos].id,
				ans[id]+=bit.sum(l,r),
				++inspos;
		}
	}
}; 
posted @ 2021-10-26 09:30  嘉年华_efX  阅读(2421)  评论(1编辑  收藏  举报