模板:数据结构

数据结构

以下数据结构均采用ll作为值类型,应用时根据需求调整。

typedef long long ll;
const ll INF=1e9;//表示(值)正无穷,且两个正无穷相加不会溢出
const int NPOS=-1;//表示(下标)不存在

离散化

在vector基础上的离散化,使用push_back()向其中插值,init()排序并离散化,ask查询离散化之后的值,at/[]运算符查离散前的值。

struct Ranker:vector<ll>
{
	void init()
	{
		sort(begin(),end()),resize(unique(begin(),end())-begin());
	}
	int ask(ll x)const
	{
		return lower_bound(begin(),end(),x)-begin();
	}
};

并查集

struct UnionFindSet:vector<int>
{
	int siz;//剩余连通块数量
	UnionFindSet(int n):siz(n)
	{
		for(int i=0; i<n; ++i)push_back(i);
	}
	int fa(int u)//u所在连通块上根节点
	{
		return at(u)!=u?at(u)=fa(at(u)):u;
	}
	void merge(int u,int w)//归并w所在连通块到u所在连通块
	{
		if(w=fa(w),u=fa(u),w!=u)at(w)=u,--siz;
	}
};

单调队列

typedef pair<int,ll> pil;
struct MonotoneQueue:deque<pil>
{
	void push(pil p,int k)//first插入元素下标,second插入值,插入并维护一个值单调递增的单调队列且队尾队首下标差值小于k
	{
		while(!empty()&&back().second>=p.second)pop_back();
		for(push_back(p); p.first-front().first>=k;)pop_front();
	}
};

ST表

O ( n log ⁡ n ) O(n\log n) O(nlogn)预处理, O ( 1 ) O(1) O(1)求静态区间最小值。

/*
//可选优化
#define log2(n) LOG2[n]
struct Log:vector<ll>
{
	Log(int N,ll E):vector<ll>(N,-1)
	{
		for(int i=1; i<N; ++i)at(i)=at(i/E)+1;
	}
} LOG2(N,2);
*/
struct SparseTable
{
	vector<vector<ll> > f;
	SparseTable(const vector<ll> &a):f(log2(a.size())+1,a)
	{
		for(int k=0; k+1<f.size(); ++k)
			for(int i=0; i+(1<<k)<a.size(); ++i)
				f[k+1][i]=min(f[k][i],f[k][i+(1<<k)]);
	}
	ll ask(int l,int r)
	{
		int k=log2(r-l+1);
		return min(f[k][l],f[k][r+1-(1<<k)]);
	}
};

树状数组

模板中Base是对应的基础版本,支持单点修改区间查询。

一维

struct Fenwick
{
	struct BaseFenwick
	{
		vector<ll> v;
		BaseFenwick(int last):v(last+1,0) {}
		void add(int x,ll w)
		{
			for(; x<v.size(); x+=x&-x)v[x]+=w;
		}
		ll ask(int x)
		{
			ll ans=0;
			for(; x; x-=x&-x)ans+=v[x];
			return ans;
		}
	};
	pair<BaseFenwick,BaseFenwick> p;
	Fenwick(int last):p(last,last) {}
	void add(int x,ll w)
	{
		p.first.add(x,w),p.second.add(x,x*w);
	}
	void add(int l,int r,ll w)
	{
		add(l,w),add(r+1,-w);
	}
	ll ask(int x)
	{
		return (x+1)*p.first.ask(x)-p.second.ask(x);
	}
	ll ask(int l,int r)
	{
		return ask(r)-ask(l-1);
	}
};

二维

高维的数据结构只要每一维维护低一维的数据即可。其余数据结构亦同理。

struct Fenwick2
{
	struct BaseFenwick2
	{
		vector<Fenwick> v;
		BaseFenwick2(int r,int c):v(r+1,c) {}
		void add(int x,int b,int t,ll w)
		{
			for(; x<v.size(); x+=x&-x)v[x].add(b,t,w);
		}
		ll ask(int x,int b,int t)
		{
			ll ans=0;
			for(; x; x-=x&-x)ans+=v[x].ask(b,t);
			return ans;
		}
	};
	pair<BaseFenwick2,BaseFenwick2> p;
	Fenwick2(int r,int c):p(BaseFenwick2(r,c),BaseFenwick2(r,c)) {}
	void add(int x,int b,int t,ll w)
	{
		p.first.add(x,b,t,w),p.second.add(x,b,t,x*w);
	}
	void add(int l,int b,int r,int t,ll w)//(l,b)~(r,t)
	{
		add(l,b,t,w),add(r+1,b,t,-w);
	}
	ll ask(int x,int b,int t)
	{
		return (x+1)*p.first.ask(x,b,t)-p.second.ask(x,b,t);
	}
	ll ask(int l,int b,int r,int t)
	{
		return ask(r,b,t)-ask(l-1,b,t);
	}
};

线段树

空间优化的线段树,支持区间查询/增加/修改/合并,使用时仅需根据实际情况修改Nodepush_upmaintainask

struct SegmentTree
{
	struct Node
	{
		ll add,set,min,sum;
	};
	vector<Node> v;
	int LAST,L,R;//序列右端点,操作序列左右端点
	SegmentTree(int n):LAST(n),v(2*n+1) {}
	void build(ll a[],int l,int r)//快速建树,调用build(a,1,n)
	{
		if(l<r)
		{
			int m=l+(r-l)/2;
			build(a,l,m),build(a,m+1,r);
			lv(l,r).set=INF,lv(l,r).add=0;//清除本节点标记
		}
		else lv(l,r).set=a[l],lv(l,r).add=0;//两个的和为a[l]即可,根据需要自行选择
		maintain(l,r);
	}
	Node &lv(int l,int r)//[l,r]对应的树上节点
	{
		return v[l+r|l!=r];
	}
	void push_down(Node &lc,Node &rc,Node &fa)//将fa的set、add标记传到lc、rc
	{
		if(fa.set!=INF)
		{
			lc.set=rc.set=fa.set,fa.set=INF;
			lc.add=rc.add=0;
		}
		lc.add+=fa.add;
		rc.add+=fa.add;
		fa.add=0;
	}
	void push_up(const Node &lc,const Node &rc,Node &fa)//将区间左右相连的lc、rc归并到fa
	{
		fa.min=min(lc.min,rc.min);
		fa.sum=lc.sum+rc.sum;
	}
	void maintain(int l,int r)//维护[l,r]
	{
		if(l<r)
		{
			int m=l+(r-l)/2;
			push_up(lv(l,m),lv(m+1,r),lv(l,r));
		}
		if(lv(l,r).set!=INF)
			lv(l,r).sum=(r-l+1)*(lv(l,r).min=lv(l,r).set);
		lv(l,r).min+=lv(l,r).add;
		lv(l,r).sum+=lv(l,r).add*(r-l+1);
	}
	Node ask(int l,int r,ll val=0,bool out=1)//查询[L,R],val为查询路径累加的add标记,out为外部调用标记,下同 
	{
		if(out)return L=l,R=r,ask(1,LAST,val,0);
		if(lv(l,r).set!=INF)
			v[0].sum=(min(R,r)-max(l,L)+1)*(v[0].min=val+lv(l,r).add+lv(l,r).set);
		else if(L<=l&&r<=R)
			v[0].min
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值