OI 模板合集

此处用于存放本喵的 OI 模板以备不时之需,不定时更新。(咕咕咕)
如果很多算法模板没有,那大概率是因为我暂时还不会/wq
upd:原来的代码基本上都炸掉了,加上修改远古的诡异码风工程浩大,在修了在修了 /qd

发现了本文的任何错误都可以私信我,会尽快修正。

有没有人浇浇这个 markdown 怎么缩进啊。排版好难受。

输入输出优化

$\qquad$int 快读
inline int read()
{
	int xr=0,F=1;char cr=getchar();
	while(cr<'0'||cr>'9') {if(cr=='-') F=-1;cr=getchar();}
	while(cr>='0'&&cr<='9')
	    xr=(xr<<3)+(xr<<1)+(cr^48),cr=getchar();
	return xr*F;
}
$\qquad$double 快读
inline double dbread()
{
   double X=0,Y=1.0; int w=0; char ch=0;
   while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
   while(isdigit(ch)) X=X*10+(ch^48),ch=getchar();
   ch=getchar();//读入小数点
   while(isdigit(ch)) X+=(Y/=10)*(ch^48),ch=getchar();
   return w?-X:X;
}
$\qquad$int 输出
void write(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

基础算法

$\qquad$归并排序
void msort(int l,int r)
{
	if(l==r) return;
	int mid=(l+r)>>1,i=l,j=mid+1,now=l;
	msort(l,mid),msort(mid+1,r);
	while(i<=mid&&j<=r) c[now++]=a[i]>a[j]?a[j++]:a[i++];
	while(i<=mid) c[now++]=a[i++];
	while(j<=r) c[now++]=a[j++];
	for(int ii=l;ii<=r;ii++) a[ii]=c[ii];
}

动态规划

DP 还存在什么板子吗(?

$\qquad$01 背包
for(int i=1;i<=m;i++)
		for(int j=t;j;j--)
			if(j-w[i]>=0) f[j]=max(f[j],f[j-w[i]]+c[i]);
	cout<<f[t]<<endl;
$\qquad$多重背包(二进制优化)
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,t,c[N],w[N];
int f[N],cnt;
int main()
{
	scanf("%d%d",&n,&t);
	for(int i=1,W,C,m;i<=n;i++)
	{
		scanf("%d%d%d",&C,&W,&m);
		int j;
		for(j=0;(1<<(j+1))-1<=m;j++)
		{
			w[++cnt]=(1<<j)*W,c[cnt]=(1<<j)*C;
		}
		w[++cnt]=W*(m-((1<<j)-1)),c[cnt]=C*(m-((1<<j)-1));
	}
	//for(int i=1;i<=cnt;i++) cout<<w[i]<<" "<<c[i]<<endl;
	for(int i=1;i<=cnt;i++)
		for(int j=t;j;j--)
			if(j-w[i]>=0) f[j]=max(f[j],f[j-w[i]]+c[i]); 
	cout<<f[t]<<endl;
	return 0;
}

图论

\(\qquad\)最短路

$\qquad$$\qquad$Floyd
for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
              f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
$\qquad$$\qquad$SPFA
void spfa(int s)
{
    for(int i=1;i<=n;i++) dis[i]=inf;
    q.push(s);
    dis[s]=0;vis[s]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
}
$\qquad$$\qquad$Dijkstra
priority_queue<pii,vector<pii>,greater<pii> >q;
void dij(int s)
{
    dis[s]=0;
    q.push(pii(0,s));
    while(!q.empty())
    {
        int u=q.top().se,f=q.top().fi;
        q.pop();
        if(f!=dis[u])continue;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to,w=e[i].w;
            if(dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                q.push(pii(dis[v],v));
            }
        }
    }
    return;
}

\(\qquad\)连通性相关

$\qquad$$\qquad$tarjan 强连通分量
stack<int> q;
void tarjan(int u)
{
	dfn[u]=++tot;low[u]=dfn[u];q.push(u);in[u]=1;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v]) {tarjan(v);low[u]=min(low[u],low[v]);}
		else if(in[v]) low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
	{
		num++;
		while(!q.empty())
		{
			if(q.top()==u) {in[u]=0,bel[u]=num,q.pop();break;}
			in[q.top()]=0,bel[q.top()]=num,q.pop();
		}
	}
}
$\qquad$$\qquad$tarjan 割点
int dfn[N],low[N],tot;
bool flag[N];
void tarjan(int u,int rt)
{
	dfn[u]=low[u]=++tot;int qwq=0;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v]) 
		{
			//cout<<u<<" "<<v<<endl;
			tarjan(v,rt);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]&&rt!=u) flag[u]=1;
			qwq++;
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(qwq>1&&u==rt) flag[u]=1;
}
$\qquad$$\qquad$tarjan 点双连通分量
void tarjan(int u,int fa)
{
	dfn[u]=low[u]=++tot;q.push(u);int son=0;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v])
		{
			son++;tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u])
			{
				num++;
				while(q.top())
				{
					ans[num].push_back(q.top());
					if(q.top()==v) {q.pop();break;}
					q.pop();
				}
				ans[num].push_back(u);
			}
		}
		else if(v!=fa) low[u]=min(low[u],dfn[v]);
	}
	if(!fa&&!son) ans[++num].push_back(u);
}
$\qquad$$\qquad$tarjan 边双连通分量(桥)
void tarjan(int u,int fa)
{
	low[u]=dfn[u]=++tot;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;if(v==fa) continue;
		if(!dfn[v])
		{
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>dfn[u]) flag[(i+1)/2]=1;
		}
		else low[u]=min(low[u],dfn[v]);
	}
}

\(\qquad\)图的匹配&网络流

$\qquad$$\qquad$匈牙利
bool dfs(int u)
{
	for(int i=1;i<=m;i++)
	{
		if(!f[u][i]||vis[i]) continue;
		vis[i]=1;
		if(mat[i]==0||dfs(mat[i])) {mat[i]=u;return 1;}
	}
	return 0;
}

for(int i=1;i<=n;i++) {ans+=dfs(i);memset(vis,0,sizeof(vis));}
$\qquad$$\qquad$EK 最大流
int vis[N],pre[N],dis[N];
bool bfs(int s,int t)
{
	for(int i=1;i<=n;i++) vis[i]=0,pre[i]=-1,dis[i]=inf;
	queue<int> q;q.push(s);
	vis[s]=1;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		if(u==t) return 1;
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to,w=e[i].w;
			if(vis[v]||!w) continue;
			vis[v]=1,pre[v]=i;
			dis[v]=min(dis[u],w);
			q.push(v);
		}
	}
	return 0;
}
void upd(int s,int t)
{
	int now=t;
	while(now!=s)
	{
		int i=pre[now];
		e[i].w-=dis[t];
		e[i^1].w+=dis[t];
		now=e[i^1].to;
	}
	ans+=dis[t];
}
$\qquad$$\qquad$Dinic 最大流
bool bfs()
{
	queue<int> q;
	for(int i=1;i<=n;i++) dis[i]=inf;
	dis[s]=0,now[s]=head[s];
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();q.pop();
		if(u==t) return 1;
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to,w=e[i].w;
			if(!w||dis[v]!=inf) continue;
			now[v]=head[v];dis[v]=dis[u]+1;
			q.push(v);
		}
	}
	return 0;
}
int dfs(int u,int sum)
{
	if(u==t) return sum;
	int res=0;
	for(int i=now[u];i&&sum;i=e[i].nxt)
	{
		int v=e[i].to,w=e[i].w;
		now[u]=i;
		if(w>0&&dis[v]==dis[u]+1)
		{
			int k=dfs(v,min(sum,w));
			if(!k) dis[v]=inf;
			e[i].w-=k;e[i^1].w+=k;
			res+=k;sum-=k;
		}
	}
	return res;
}
$\qquad$$\qquad$EK 费用流
bool spfa()
{
	queue<int> q;
	for(int i=1;i<=n;i++) dis[i]=mn[i]=inf,pre[i]=-1,in[i]=0;
	dis[s]=0,in[s]=1;q.push(s);
	while(!q.empty())
	{
		int u=q.front();q.pop();in[u]=0;
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to,w=e[i].w;
			if(!w) continue;
			if(dis[v]>dis[u]+e[i].c)
			{
				dis[v]=dis[u]+e[i].c;
				mn[v]=min(mn[u],e[i].w);
				pre[v]=i;
				if(!in[v]) in[v]=1,q.push(v);
			}
		}
	}
	if(dis[t]==inf) return 0;
	else return 1;
}
int ans1,ans2;
void upd()
{
	int now=t;
	while(now!=s)
	{
		int i=pre[now];
		e[i].w-=mn[t],e[i^1].w+=mn[t];
		now=e[i^1].to;
	}
	ans1+=mn[t];ans2+=dis[t]*mn[t];
}
$\qquad$$\qquad$2-SAT
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
const int M=4e6+5;
int n,m,a[N];
int head[N],cnt;
struct node{
	int nxt,to;
}e[M];
void add(int u,int v){
	e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
int dfn[N],low[N],tot,vis[N];
int bel[N],qwq;
stack<int> q;
void tarjan(int s)
{
	vis[s]=1;
	low[s]=dfn[s]=++tot;
	q.push(s);
	for(int i=head[s];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v]) {tarjan(v);low[s]=min(low[s],low[v]);}
		else if(vis[v]) low[s]=min(low[s],dfn[v]);
	}
	if(dfn[s]==low[s])
	{
		qwq++;
		while(1)
		{
			int u=q.top();
			bel[u]=qwq;vis[u]=0;
			q.pop();
			if(u==s) break;
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,x,a,y,b;i<=m;i++)
	{
		scanf("%d%d%d%d",&x,&a,&y,&b);
		add(x+n*a,y+n*(b^1));add(y+n*b,x+n*(a^1));
	}
	for(int i=1;i<=2*n;i++) 
		if(!dfn[i]) tarjan(i);
	for(int i=1;i<=n;i++)
	{
		if(bel[i]==bel[i+n])
		{
			cout<<"IMPOSSIBLE"<<endl;
			return 0;
		}
	}
	cout<<"POSSIBLE"<<endl;
	for(int i=1;i<=n;i++)
	{
		if(bel[i]<bel[i+n]) cout<<"1 ";
		else cout<<"0 ";
	}
	cout<<endl;
	return 0;
}

\(\qquad\)树上问题

$\qquad$$\qquad$kruskal
bool cmp(node a,node b){
    return a.w<b.w;
}
int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
int main()
{
    scanf("%d%d",&n,&m); 
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        if(find(e[i].u)==find(e[i].v)) continue;
        ans+=e[i].w;
        fa[find(e[i].v)]=find(e[i].u);
        if(cnt==n-2) {cnt++;break;}
    }
    printf("%d",ans);
    return 0;
}
$\qquad$$\qquad$堆优化 Prim
int vis[N];
priority_queue<pii,vector<pii>,greater<pii> >q;
int Prim(int s)
{
	int ans=0;
	q.push(pii(0,s));
	while(!q.empty())
	{
		int w=q.top().fi,u=q.top().se;q.pop();
		if(vis[u]) continue;
		ans=max(ans,w);vis[u]=1;
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to;
			if(vis[v]) continue;
			q.push(pii(e[i].w,v));
		}
	}
	return ans;
}
$\qquad$$\qquad$倍增 LCA
void init(int now,int fa)
{
	f[now][0]=fa;
	dep[now]=dep[fa]+1;
	for(int i=1;i<=lg[dep[now]];i++)
	{
		f[now][i]=f[f[now][i-1]][i-1];
	}
	for(int i=head[now];i;i=e[i].nxt)
	{
		if(e[i].t!=fa) init(e[i].t,now);
	}
}
int LCA(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	while(dep[x]>dep[y]) x=f[x][lg[dep[x]-dep[y]]-1];
	if(x==y) return x;
	for(int k=lg[dep[x]]-1;k>=0;k--)
	{
		if(f[x][k]!=f[y][k]) x=f[x][k],y=f[y][k];
	}
	return f[x][0];
}
$\qquad$$\qquad$树剖(重链剖分)
void dfs1(int now,int deep,int f)
{
	int maxn=-inf;
	siz[now]=1;fa[now]=f;dep[now]=deep;
	for(int i=head[now];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==f) continue;
		dfs1(v,deep+1,now);
		siz[now]+=siz[v];
		if(siz[v]>maxn) maxn=siz[v],son[now]=v;
	}
}
void dfs2(int now,int tp)
{
	dfn[now]=++tot;top[now]=tp;a[tot]=s[now];
	if(!son[now]) return;
	dfs2(son[now],tp);
	for(int i=head[now];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa[now]||v==son[now]) continue;
		dfs2(v,v);
	}
}
void q1(int x,int y,int k)//x到y路径上权值+k
{
	k%=p;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		modify(1,1,n,dfn[top[x]],dfn[x],k);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	modify(1,1,n,dfn[y],dfn[x],k);
}
int q2(int x,int y)//x到y路径权值和
{
	int sum=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		sum=(sum+query(1,1,n,dfn[top[x]],dfn[x]))%p;
		x=fa[top[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	sum=(sum+query(1,1,n,dfn[y],dfn[x]))%p;
	return sum;
}
void q3(int now,int k){//x子树加k
	modify(1,1,n,dfn[now],siz[now]+dfn[now]-1,k);
}
int q4(int now){//x子树权值和
	return query(1,1,n,dfn[now],siz[now]+dfn[now]-1)%p;
}
$\qquad$$\qquad$prufer 序列
namespace sub1
{
	int fa[N],a[N],son[N];
	void solve()
	{
		for(int i=1;i<n;i++) fa[i]=read(),son[fa[i]]++;
		for(int i=1,j=1;i<=n-2;i++,j++)
		{
			while(son[j]) j++;
			a[i]=fa[j];
			while(i<=n-2&&!(--son[a[i]])&&a[i]<j) a[i+1]=fa[a[i]],i++;
		}
		int ans=0;
		for(int i=1;i<=n-2;i++) ans^=i*a[i];
		printf("%lld\n",ans);
	}
}
namespace sub2
{
	int fa[N],a[N],son[N];
	void solve()
	{
		for(int i=1;i<=n-2;i++) a[i]=read(),son[a[i]]++;
		a[n-1]=n;
		for(int i=1,j=1;i<n;i++,j++)
		{
			while(son[j]) j++;
			fa[j]=a[i];
			while(i<n&&!(--son[a[i]])&&a[i]<j) fa[a[i]]=a[i+1],i++;
		}
		int ans=0;
		for(int i=1;i<n;i++) ans^=i*fa[i];
		printf("%lld\n",ans);
	}
}
$\qquad$$\qquad$点分治
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int xr=0,F=1;char cr=getchar();
	while(cr<'0'||cr>'9') {if(cr=='-') F=-1;cr=getchar();}
	while(cr>='0'&&cr<='9')
	    xr=(xr<<3)+(xr<<1)+(cr^48),cr=getchar();
	return xr*F;
}
const int N=1e4+5,M=1e7+5;
int n,m;
int head[N],cnt;
struct node{
	int nxt,to,w;
}e[N<<1];
void add(int u,int v,int w){
	e[++cnt]={head[u],v,w};head[u]=cnt;
}
int S,vis[N],siz[N],rt,mx[N];
void find(int now,int fa)
{
	siz[now]=1,mx[now]=0;
	for(int i=head[now];i;i=e[i].nxt)
	{
		int v=e[i].to;if(v==fa||vis[v]) continue;
		find(v,now);
		siz[now]+=siz[v];
		mx[now]=max(mx[now],siz[v]);
	}
	mx[now]=max(mx[now],S-siz[now]);
	if(mx[now]<mx[rt]) rt=now;
}
int dis[N],tot,rem[N];
void getdis(int now,int fa)
{
	//cout<<now<<" "<<fa<<endl;
	rem[++tot]=dis[now];
	for(int i=head[now];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa||vis[v]) continue;
		dis[v]=dis[now]+e[i].w,getdis(v,now);
	}
}
int qwq[N],q[N],t[M],flag[N];
void calc(int now)
{
	int p=0;
	for(int i=head[now];i;i=e[i].nxt)
	{
		int v=e[i].to;if(vis[v]) continue;
		dis[v]=e[i].w;tot=0;
		getdis(v,now);
		for(int j=1;j<=tot;j++)
			for(int k=1;k<=m;k++)
				if(q[k]>=rem[j]) flag[k]|=t[q[k]-rem[j]];
		for(int j=1;j<=tot;j++) 
			if(rem[j]<=1e7) qwq[++p]=rem[j],t[rem[j]]=1; 
	}
	for(int i=1;i<=p;i++) t[qwq[i]]=0;
}
void solve(int now)
{
	//cout<<"solve"<<now<<endl;
	vis[now]=1;
	calc(now);
	for(int i=head[now];i;i=e[i].nxt)
	{
		int v=e[i].to;if(vis[v]) continue;
		S=siz[v];rt=0,mx[rt]=n; 
		find(v,now);
		solve(rt);
	}
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read(),w=read();
		add(u,v,w),add(v,u,w);
	}
	for(int i=1;i<=m;i++) scanf("%d",&q[i]);
	rt=0,mx[0]=n,t[0]=1,S=n;
	solve(1);
	for(int i=1;i<=m;i++) 
		printf(flag[i]?"AYE\n":"NAY\n");
	return 0;
}

数学

\(\qquad\)线性代数

$\qquad$$\qquad$快速幂
int qpow(int n,int k)
{
	int res=1;
	for(;k;n=n*n%mod,k>>=1)
		if(k&1) res=res*n%mod;
	return res;
}
$\qquad$$\qquad$矩阵快速幂
struct matrix{
	int f[N][N];
	matrix(){memset(f,0,sizeof(f));}
};
matrix operator * (const matrix &x,const matrix &y)
{
	matrix res;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=n;k++)
				res.f[i][j]=(x.f[i][k]*y.f[k][j]+res.f[i][j])%p;
	return res;
}
matrix qpow(matrix a,int k)
{
	matrix ans;
	for(int i=1;i<=n;i++) ans.f[i][i]=1;
	while(k>0)
	{
		if(k&1) ans=ans*a;
		a=a*a;k>>=1;
	}
	return ans;
}
$\qquad$$\qquad$高斯消元
for(int i=1;i<=n;i++)
{
	int flag=0;
	for(int j=i;j<=n;j++)
	{
		if(abs(a[j][i])>eps)
		{
			flag=j;
			break;
		}
	}
	if(!flag) 
	{
		cout<<"No Solution"<<endl;
		return 0;
	}
	for(int j=1;j<=n;j++)
	{
		if(j==flag) continue;
		double K=a[j][i]/a[flag][i];
		for(int k=1;k<=n+1;k++)
		{
			a[j][k]-=a[flag][k]*K;
		}
	}
}
for(int i=1;i<=n;i++) printf("%.2lf\n",a[i][n+1]/a[i][i]);
$\qquad$$\qquad$线性基
void insert(int x)
{
	for(int i=50;i>=0;i--)
	{
		if((x&(1ll<<i))==0) continue;
		if(!p[i]) {p[i]=x;break;}
		else x^=p[i];
	}
}

\(\qquad\)数论

$\qquad$$\qquad$欧拉函数
int now=m;
for(int i=2;i*i<=m;i++)
{
	if(now%i==0)
	{
		phi=phi*(i-1)/i;
		while(now%i==0) now/=i;
	}
}
if(now>1) phi=phi*(now-1)/now;
$\qquad$$\qquad$exgcd
void exgcd(int a,int b)
{
	if(!b)
	{
		x=1,y=0;
		return;
	}
	exgcd(b,a%b);
	int x0=x,y0=y;
	x=y0;y=x0-(a/b)*y0;
}
$\qquad$$\qquad$Lucas 定理
int c(int n,int m){
	if(m>n) return 0;
	return jc[n]*qpow(jc[m],mod-2)%mod*qpow(jc[n-m],mod-2)%mod;
}
int lucas(int n,int m){
	if(!m) return 1;
	return lucas(n/mod,m/mod)*c(n%mod,m%mod)%mod;
}
$\qquad$$\qquad$原根
inline bool check1(int x)//check原根存在性 
{
	if(x==2||x==4) return 1;
	if(x%2==0) x/=2;
	if(x%2==0) return 0;
	//bool flag=0;
	for(int i=2;i*i<=x;i++)
	{
		if(x%i==0)
		{
			while(x%i==0) x/=i;
			return (x==1);
		}
	}
	return 1;
}
inline bool check2(int x,int n)//判定合法性
{
	if(__gcd(x,n)>1) return 0;
	int m=phi[n];tot=0;
	for(int i=2;i*i<=m;i++) 
	{
		if(m%i==0)
		{
			fac[++tot]=i;
			while(m%i==0) m/=i;
		}
	}
	if(m>1) fac[++tot]=m;
	for(int i=1;i<=tot;i++)
		if(qpow(x,phi[n]/fac[i],n)==1) return 0;
	return 1;
}
$\qquad$$\qquad$BSGS
#define int long long
int p,b,n;
unordered_map<int,int> mp;
int qpow(int n,int k)
{
	int res=1;
	for(;k;n=n*n%p,k>>=1)
		if(k&1) res=res*n%p;
	return res;
}
signed main()
{
	p=read(),b=read(),n=read();
	//cout<<p<<" "<<b<<" "<<n<<endl;
	int t=sqrt(p); if(t*t<p) t++;
	for(int i=0;i<=t;i++) 
	{
		//cout<<n*qpow(b,i)%p<<endl;
		mp[n*qpow(b,i)%p]=i;
	}
	for(int i=1;i<=t;i++)
	{
		if(mp[qpow(b,t*i)])
		{
			printf("%lld\n",t*i-mp[qpow(b,t*i)]); 
			return 0;
		}
	}
	printf("no solution\n");
	return 0;
}
$\qquad\qquad$exBSGS
const int P=1e7-9;
const int N=1e7+5;
struct hsh{
	int w,val,nxt;
}e[N];
int head[N],tt;
void ins(int x,int val)
{
	for(int i=head[x%P];i;i=e[i].nxt) if(e[i].w==x) {e[i].val=val;return;}
	e[++tt]={x,val,head[x%P]};head[x%P]=tt;
}
int find(int x)
{
	for(int i=head[x%P];i;i=e[i].nxt) if(e[i].w==x) return e[i].val;
	return 0;
}
int BSGS(int a,int n,int p,int ad)
{
	int t=ceil(sqrt(p)),s=1;
//	tt=0;
//	for(int i=1;i<=t;i++) s=1ll*s*a%p,head[(1ll*s*n%p)%P]=0;
//	s=1;
	for(int i=1;i<=t;i++) s=1ll*s*a%p,ins(1ll*s*n%p,i);
	int qwq=s;s=ad;
	for(int i=0;i<=t;i++,s=1ll*s*qwq%p)
	{
		if(find(s)&&1ll*i*t-find(s)>0) 
		{
			int res=1ll*i*t-find(s),ss=1;tt=0;
			for(int i=1;i<=t;i++) ss=1ll*ss*a%p,head[(1ll*ss*n%p)%P]=0;
			return res;
		}
	}
	s=1;tt=0;
	for(int i=1;i<=t;i++) s=1ll*s*a%p,head[(1ll*s*n%p)%P]=0;
	return -1;
}
int exBSGS(int a,int n,int p)
{
	a%=p,n%=p;
	if(n==1||p==1) return 0;
	int cnt=0,ad=1;
	while("qwq")
	{
		int d=__gcd(a,p);
		if(d==1) break;
		if(n%d) return -1;
		cnt++;n/=d,p/=d;
		ad=(1ll*ad*a/d)%p;
		if(ad==n) return cnt;
	}
	int ans=BSGS(a,n,p,ad);
	return ans==-1?-1:ans+cnt;
}
signed main()
{
	while("pap")
	{
		int a=read(),p=read(),n=read();
		if(!a) return 0;
		int ans=exBSGS(a,n,p);
		if(ans==-1) printf("No Solution\n");
		else printf("%d\n",ans);
	}
	return 0;
}
$\qquad$$\qquad$类欧几里得
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353,inv2=499122177,inv6=166374059;
int T,n,a,b,c;
struct node{
	int f=0,g=0,h=0;
};
node solve(int a,int b,int c,int n)
{
	node d;
	if(!a)
	{
		d.f=(b/c)*(n+1)%mod;
		d.g=n*(n+1)%mod*inv2%mod*(b/c)%mod;
		d.h=(b/c)*(b/c)%mod*(n+1)%mod;
	}
	else if(a>=c||b>=c)
	{
		node q=solve(a%c,b%c,c,n);
		d.f=((n*(n+1)%mod*inv2%mod*(a/c)%mod+(n+1)*(b/c)%mod+q.f)+mod)%mod;
		d.g=((a/c)*n%mod*(n+1)%mod*(2*n+1)%mod*inv6%mod+(b/c)*n%mod*(n+1)%mod*inv2%mod+q.g)%mod;
		d.h=(2*(b/c)%mod*q.f%mod+2*(a/c)%mod*q.g%mod+(a/c)*(a/c)%mod*n%mod*(n+1)%mod*(2*n+1)%mod*inv6%mod+(b/c)*(b/c)%mod*(n+1)%mod+(a/c)*(b/c)%mod*n%mod*(n+1)%mod+q.h)%mod;
	}
	else
	{
		int m=(a*n+b)/c;
		node q=solve(c,c-b-1,a,m-1);
		d.f=(n*m%mod-q.f+mod)%mod;
		d.g=(((m*n%mod*(n+1)%mod-q.h-q.f)%mod)+mod)%mod*inv2%mod;
		d.h=((n*m%mod*(m+1)%mod-2*q.g%mod-2*q.f%mod-d.f)%mod+mod)%mod;
	}
	//cout<<a<<" "<<b<<" "<<c<<" "<<n<<" "<<d.f<<" "<<d.g<<" "<<d.h<<endl; 
	return d;
}
signed main()
{
	scanf("%lld",&T); 
	while(T--)
	{
		scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
		node ans=solve(a,b,c,n);
		cout<<ans.f%mod<<" "<<ans.h%mod<<" "<<ans.g%mod<<endl;
	}
	return 0;
}

\(\qquad\)筛法

$\qquad$$\qquad$埃氏筛
bool flag[N];
void Eratosthenes(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(flag[i])continue;
        for(int j=2;j*i<=n;j++) flag[j*i]=1;
    }
}
$\qquad$$\qquad$欧拉筛
for(int i=2;i<=n;i++)
	{
		if(!flag[i]) p[++cnt]=i;
		for(int j=1;j<=cnt&&i*p[j]<=n;j++) 
		{
			flag[i*p[j]]=1;
			if(!i%p[j]) break;
		}
	}
$\qquad$$\qquad$线性筛欧拉函数
phi[1]=1;
for(int i=2;i<=n;i++)
{
	if(!flag[i]) {p[++cnt]=i;phi[i]=i-1;}
	for(int j=1;j<=cnt&&i*p[j]<=n;j++)
	{
		flag[i*p[j]]=1;
		if(!(i%p[j])) {phi[i*p[j]]=phi[i]*p[j];break;}
		else phi[i*p[j]]=phi[i]*(p[j]-1);
	}
}
$\qquad$$\qquad$线性筛莫比乌斯函数
mu[1]=1;
for(int i=2;i<=mx;i++)
{
	if(!flag[i]) p[++cnt]=i,mu[i]=-1;
	for(int j=1;j<=cnt&&i*p[j]<=mx;j++)
	{
		flag[i*p[j]]=1;
		if(i%p[j]) mu[i*p[j]]=mu[i]*mu[p[j]];
		else {mu[i*p[j]]=0;break;}
	}
}
$\qquad$$\qquad$杜教筛
int getmu(int n)
{
	if(n<=5e6) return mu[n];
	else if(mpmu[n]) return mpmu[n];
	int res=1;
	for(int l=2,r;l<=n;l=r+1)
	{
		r=min(n,n/(n/l));
		res-=(r-l+1)*getmu(n/l);
	}
	return mpmu[n]=res;
}
int getphi(int n)
{
	if(n<=5e6) return phi[n];
	else if(mpphi[n]) return mpphi[n];
	int res=(n+1)*n/2;
	for(int l=2,r;l<=n;l=r+1)
	{
		r=min(n,n/(n/l));
		res-=(r-l+1)*getphi(n/l);
	}
	return mpphi[n]=res;
}

\(\qquad\)多项式

$\qquad$$\qquad$递归版 FFT
void FFT(int limit,Complex a[],int op)
{
	if(limit==1) return;
	Complex a1[(limit>>1)+5],a2[(limit>>1)+5];
	for(int i=0;i<=limit;i+=2) a1[i>>1]=a[i],a2[i>>1]=a[i+1];
	FFT(limit>>1,a1,op),FFT(limit>>1,a2,op);
	Complex Wn={cos(2.0*pai/limit),sin(2.0*pai/limit)*op},w={1,0};
	for(int i=0;i<(limit>>1);i++,w=w*Wn)
	{
		a[i]=a1[i]+w*a2[i];
		a[i+(limit>>1)]=a1[i]-w*a2[i];
	}
}
int main()
{
	n=read(),m=read();
	for(int i=0;i<=n;i++) a[i].x=read();
	for(int i=0;i<=m;i++) b[i].x=read();
	int w=1;while(w<=m+n) w<<=1;
	FFT(w,a,1),FFT(w,b,1);
	for(int i=0;i<=w;i++) a[i]=a[i]*b[i];
	FFT(w,a,-1);
	for(int i=0;i<=n+m;i++) printf("%d ",(int)(a[i].x/w+0.5));
	return 0;
}

数据结构

$\qquad$路径压缩并查集
int find(int x)
{
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}
$\qquad$单调栈
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
q.push(n);
for(int i=n-1;i;i--)
{
	//cout<<i<<endl;
	if(!q.empty()) 
	{
		while(!q.empty()&&a[i]>=a[q.top()]) q.pop();
		if(!q.empty()) ans[i]=q.top();
	}
	q.push(i);
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
$\qquad$单调队列
int main()
{
  	scanf("%d%d",&n,&k);
  	for(int i=1;i<=n;i++)
    {
    	scanf("%d",&a[i].w);
      	node x;
      	x.w=a[i].w;x.id=i;
      	while(!q.empty()&&q.back().w>=a[i].w) q.pop_back();
      	q.push_back(x);
      	while(q.front().id<=i-k) q.pop_front();
      	if(i>=k) cout<<q.front().w<<" ";
    }
  	cout<<endl;
  	q.clear();
  	for(int i=1;i<=n;i++)
    {
      	node x;
      	x.w=a[i].w;x.id=i;
      	while(!q.empty()&&q.back().w<=a[i].w) q.pop_back();
      	q.push_back(x);
      	while(q.front().id<=i-k) q.pop_front();
      	if(i>=k) cout<<q.front().w<<" ";
    }
  	return 0;
}
$\qquad$ST表
int f[1000001][21],m,n;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&f[i][0]);
    for(int j=1;j<=21;j++)
    {
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        }
    }
    for(int i=1;i<=m;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        int k=log2(r-l+1); 
        printf("%d\n",max(f[l][k],f[r-(1<<k)+1][k]));
    }
    return 0;
}
$\qquad$树状数组
ll lowbit(ll x){
	return x&(-x);
}
void update(ll x,ll y){
	for(ll i=x;i<=n;i+=lowbit(i)) c[i]+=y;
}
ll sum(ll x)
{
	ll res=0;
	for(ll i=x;i;i-=lowbit(i)) res+=c[i];
	return res;
}
$\qquad$线段树
#include<bits/stdc++.h>
#define ls now<<1
#define rs now<<1|1
using namespace std;
typedef long long ll;
const ll N=1e5+5;
ll n,m;
ll a[N],tr[N<<2],lz[N<<2];
void build(ll now,ll l,ll r)
{
	if(l==r)
	{
		tr[now]=a[l];
		return;
	}
	ll mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	tr[now]=tr[ls]+tr[rs];
}
void push_down(ll now,ll l,ll r,ll mid)
{
	if(lz[now]==0) return;
	lz[ls]+=lz[now];lz[rs]+=lz[now];
	tr[ls]+=lz[now]*(mid-l+1);
	tr[rs]+=lz[now]*(r-mid);
	lz[now]=0;
}
void add(ll now,ll l,ll r,ll ml,ll mr,ll k)
{
	if(l==ml&&r==mr)
	{
		tr[now]+=k*(r-l+1);
		lz[now]+=k;
		return;
	}
	ll mid=(l+r)>>1;
	push_down(now,l,r,mid);
	if(mr<=mid) add(ls,l,mid,ml,mr,k);
	else if(ml>mid) add(rs,mid+1,r,ml,mr,k);
	else
	{
		add(ls,l,mid,ml,mid,k);
		add(rs,mid+1,r,mid+1,mr,k);
	}
	tr[now]=tr[ls]+tr[rs];
}
ll ask(ll now,ll l,ll r,ll ml,ll mr)
{
	//cout<<l<<" "<<r<<" "<<ml<<" "<<mr<<endl;
	if(l==ml&&r==mr) return tr[now];
	ll mid=(l+r)>>1;
	push_down(now,l,r,mid);
	if(mr<=mid) return ask(ls,l,mid,ml,mr);
	else if(ml>mid) return ask(rs,mid+1,r,ml,mr);
	else return ask(ls,l,mid,ml,mid)+ask(rs,mid+1,r,mid+1,mr);
}
int main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		ll op,s,t,k;
		scanf("%lld",&op);
		if(op==1)
		{
			scanf("%lld%lld%lld",&s,&t,&k);
			add(1,1,n,s,t,k);
		}
		else
		{
			scanf("%lld%lld",&s,&t);
			cout<<ask(1,1,n,s,t)<<endl;
		}
	}
	return 0;
}
$\qquad$主席树
#include<bits/stdc++.h>
#define ls (tr[now].l)
#define rs (tr[now].r)
using namespace std;
const int N=1e6+5;
int n,m,cnt;
int a[N],rt[N];
struct node{
	int l,r,v;
}tr[N<<5];
int add(int now)
{
	tr[++cnt]=tr[now];
	return cnt;
}
int build(int now,int l,int r)
{
	now=++cnt;
	if(l==r)
	{
		tr[now].v=a[l];
		return now;
	}
	int mid=(l+r)>>1;
	tr[now].l=build(ls,l,mid);
	tr[now].r=build(rs,mid+1,r);
	return now;
}
int modify(int now,int l,int r,int x,int k)
{
	now=add(now);
	if(l==r)
	{
		tr[now].v=k;
		return now;
	}
	int mid=(l+r)>>1;
	if(x<=mid) tr[now].l=modify(ls,l,mid,x,k);
	else tr[now].r=modify(rs,mid+1,r,x,k);
	return now;
}
int query(int now,int l,int r,int x)
{
	if(l==r) return tr[now].v;
	int mid=(l+r)>>1;
	if(x<=mid) return query(ls,l,mid,x);
	else return query(rs,mid+1,r,x);
}
signed main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	rt[0]=build(0,1,n);
	for(int i=1;i<=m;i++)
	{
		int v,op,x,k;
		scanf("%d%d%d",&v,&op,&x);
		if(op==1)
		{
			scanf("%d",&k);
			rt[i]=modify(rt[v],1,n,x,k);
		}
		else
		{
			cout<<query(rt[v],1,n,x)<<endl;
			rt[i]=rt[v];
		}
	}
	return 0;
}
$\qquad$主席树 2
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,a[N],t[N],rt[N],cnt;
struct node{
	int l,r,w;
}tr[N<<5];
int add(int now)
{
	tr[++cnt]=tr[now];
	return cnt;
}
int build(int now,int l,int r)
{
	now=++cnt;
	if(l==r) return now;
	int mid=(l+r)>>1;
	tr[now].l=build(tr[now].l,l,mid);
	tr[now].r=build(tr[now].r,mid+1,r);
	return now;
}
int modify(int now,int l,int r,int x)
{
	now=add(now);
	if(l==r)
	{
		tr[now].w++;
		return now;
	}
	tr[now].w++;
	int mid=(l+r)>>1;
	if(x<=mid) tr[now].l=modify(tr[now].l,l,mid,x);
	else tr[now].r=modify(tr[now].r,mid+1,r,x);
	return now;
}
int query(int vl,int vr,int l,int r,int x)
{
	if(l==r) return l;
	int mid=(l+r)>>1;
	int k=tr[tr[vr].l].w-tr[tr[vl].l].w;
	if(k>=x) return query(tr[vl].l,tr[vr].l,l,mid,x);
	else return query(tr[vl].r,tr[vr].r,mid+1,r,x-k);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) {scanf("%d",&a[i]);t[i]=a[i];}
	sort(t+1,t+n+1);
	
	int ll=unique(t+1,t+n+1)-t-1;
	rt[0]=build(0,1,ll);
	for(int i=1;i<=n;i++)
	{
		a[i]=lower_bound(t+1,t+ll+1,a[i])-t;
		rt[i]=modify(rt[i-1],1,ll,a[i]);
	}
	//for(int i=1;i<=n;i++) cout<<a[i]<<" "<<endl;
	for(int i=1;i<=m;i++)
	{
		int l,r,k;
		scanf("%d%d%d",&l,&r,&k);
		cout<<t[query(rt[l-1],rt[r],1,ll,k)]<<endl;
	}
	return 0;
}
$\qquad$线段树合并
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+5;
int x[N],y[N],z[N];
int n,m,head[N],cnt,mx,rt[N],tot,ans[N];
int sum[N],dep[N],fa[N],son[N],top[N];
struct node{
	int nxt,to;
}e[N];
struct node1{
	int tim,mx,l,r;
}tr[N];
void add(int u,int v){
	e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
void dfs1(int x,int f)
{
	dep[x]=dep[f]+1;fa[x]=f;sum[x]=1;
	for(int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==f) continue;
		dfs1(v,x);
		if(sum[v]>sum[son[x]]) son[x]=v;
		sum[x]+=sum[v];
	}
}
void dfs2(int x)
{
	if(son[fa[x]]==x) top[x]=top[fa[x]];
	else top[x]=x;
	for(int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa[x]) continue;
		dfs2(v);
	}
}
int lca(int x,int y)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y]) return x;
	else return y;
}
int modify(int now,int l,int r,int x,int k)
{
	if(!now) now=++tot;
	if(l==r)
	{
		tr[now].tim+=k;
		tr[now].mx=x;
		//cout<<"qwq "<<x<<" "<<l<<" "<<r<<endl;
		return now;
	}
	int mid=(l+r)>>1;
	if(x<=mid) tr[now].l=modify(tr[now].l,l,mid,x,k);
	else tr[now].r=modify(tr[now].r,mid+1,r,x,k);
	if(tr[tr[now].l].tim>=tr[tr[now].r].tim) {tr[now].tim=tr[tr[now].l].tim;tr[now].mx=tr[tr[now].l].mx;}
	else {tr[now].tim=tr[tr[now].r].tim;tr[now].mx=tr[tr[now].r].mx;}
	return now;
}
int merge(int a,int b,int l,int r)
{
	if((!a)) return b;if((!b)) return a;
	int mid=(l+r)>>1;
	if(l==r)
	{
		tr[a].tim+=tr[b].tim;tr[a].mx=l;
		return a;
	}
	tr[a].l=merge(tr[a].l,tr[b].l,l,mid);
	tr[a].r=merge(tr[a].r,tr[b].r,mid+1,r);
	if(tr[tr[a].l].tim>=tr[tr[a].r].tim) {tr[a].tim=tr[tr[a].l].tim;tr[a].mx=tr[tr[a].l].mx;}
	else {tr[a].tim=tr[tr[a].r].tim;tr[a].mx=tr[tr[a].r].mx;}
	return a;
}
void dfs3(int x)
{
	for(int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa[x]) continue;
		dfs3(v);
		rt[x]=merge(rt[x],rt[v],1,mx);
	}
	if(tr[rt[x]].tim) ans[x]=tr[rt[x]].mx;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,u,v;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x[i],&y[i],&z[i]);
		mx=max(mx,z[i]);
	}
	dfs1(1,0);dfs2(1);
	//for(int i=1;i<=n;i++) cout<<top[i]<<endl;
	for(int i=1;i<=m;i++)
	{
		int l=lca(x[i],y[i]);
		//cout<<l<<" "<<x[i]<<" "<<y[i]<<endl;
		rt[x[i]]=modify(rt[x[i]],1,mx,z[i],1);
		rt[y[i]]=modify(rt[y[i]],1,mx,z[i],1);
		rt[l]=modify(rt[l],1,mx,z[i],-1);
		if(fa[l]) rt[fa[l]]=modify(rt[fa[l]],1,mx,z[i],-1);
	}
	dfs3(1);
	for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
	return 0;
}
$\qquad$李超线段树
#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1) 
using namespace std;
typedef double db;
const int N=1e5+5; 
const db eps=1e-9;
int n,lastans=0,cnt;
int tr[N<<2],ans;
db maxn;
struct node {db k,b;}a[N];
db gety(int id,db x){
    if(id==0) return 0;
    return a[id].k*x+a[id].b;
}
int readx(int x) {return (x+lastans-1)%39989+1;}
int ready(int x) {return (x+lastans-1)%1000000000+1;}
void modify(int now,int l,int r,int ml,int mr,int id)
{
    int mid=(l+r)>>1;
    if(l==ml&&r==mr)
    {
        int trw=tr[now];
        if(gety(id,mid)>gety(tr[now],mid)) tr[now]=id;
        if(gety(id,l)-gety(trw,l)>-eps&&gety(id,r)-gety(trw,r)>-eps) return;
        else if(gety(id,l)-gety(trw,l)<eps&&gety(id,r)-gety(trw,r)<eps) return;
        if(gety(id,mid)>gety(trw,mid)) {modify(ls,l,mid,ml,mid,trw);modify(rs,mid+1,r,mid+1,mr,trw);}
        else {modify(ls,l,mid,ml,mid,id);modify(rs,mid+1,r,mid+1,mr,id);}
    }
    if(mr<=mid) modify(ls,l,mid,ml,mr,id);
    else if(ml>mid) modify(rs,mid+1,r,ml,mr,id);
    else {modify(ls,l,mid,ml,mid,id);modify(rs,mid+1,r,mid+1,mr,id);}
}
void query(int now,int l,int r,int x)
{
    int mid=(l+r)>>1;
    if(gety(tr[now],x)>maxn||(gety(tr[now],x)==maxn&&tr[now]<ans)) ans=tr[now],maxn=gety(tr[now],x);
    if(l==r) return;
    if(x<=mid) query(ls,l,mid,x);
    else query(rs,mid+1,r,x);
}
int main()
{
    scanf("%d",&n);
    for(int i=1,op,xa,ya,xb,yb;i<=n;i++) 
    {
        scanf("%d",&op);
        if(op==0)
        {
            scanf("%d",&xa);xa=readx(xa);
            maxn=0.0,ans=0;
            query(1,1,40000,xa);
            cout<<ans<<endl;
            lastans=ans;
        }
        else
        {
            scanf("%d%d%d%d",&xa,&ya,&xb,&yb);
            xa=readx(xa);xb=readx(xb);ya=ready(ya);yb=ready(yb);
            if(xa>xb) {swap(xa,xb);swap(ya,yb);}
            db k=0.0,b=0.0;
            if(xa==xb) k=0.0,b=yb;
            else 
            {
                k=(db)(yb-ya)/(db)(xb-xa);
                b=(db)yb-k*(db)xb;
            }
            a[++cnt]={k,b};
            modify(1,1,40000,xa,xb,cnt); 
        }
    }
    return 0;
}
$\qquad$哈夫曼树
#include<bits/stdc++.h>
#define int long long
#define pii pair<long long,long long>
#define fi first
#define se second
using namespace std;
const int N=1e5+5;
int n,k,w[N],ans;
priority_queue<pii,vector<pii>,greater<pii> > q;
signed main()
{
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&w[i]);
		q.push(pii(w[i],0)); 
	}
	while((q.size()-1)%(k-1)) q.push(pii(0,0)); 
	while(q.size()>1)
	{
		int sum=0,maxn=0;
		for(int i=1;i<=k;i++)
		{
			if(q.empty()) break;
			sum+=q.top().fi;
			maxn=max(maxn,q.top().se);
			q.pop();
		}
		ans+=sum;
		q.push(pii(sum,maxn+1));
	}
	cout<<ans<<"\n"<<q.top().se<<endl;
	return 0;
}
$\qquad$笛卡尔树
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e7+5;
inline int read()
{
	int xr=0;char cr;
	cr=getchar();
	while(cr<'0'||cr>'9') cr=getchar();
	while(cr>='0'&&cr<='9') xr=(xr<<3)+(xr<<1)+(cr^48),cr=getchar();
	return xr;
}
struct node{
	int l,r;
}tr[N];
int n,a[N],w[N];
int q[N],st;
inline void build()
{
	for(int i=1;i<=n;i++)
	{
		int x=a[i],now=0;
		while(st&&a[q[st]]>x) now=q[st],st--;
		if(st) tr[q[st]].r=i;
		if(now) tr[i].l=now;
		q[++st]=i;
	}
}
signed main()
{
	n=read();
	for(int i=1;i<=n;i++) a[i]=read(),w[a[i]]=i;
	build(); 
	ll ansl=0,ansr=0;
	for(int i=1;i<=n;i++)
	{
		ansl^=1ll*i*(tr[i].l+1);
		ansr^=1ll*i*(tr[i].r+1);
		//cout<<tr[i].l<<" "<<tr[i].r<<endl;
	}
	printf("%lld %lld",ansl,ansr);
	//cout<<ansl<<" "<<ansr<<endl;
	return 0;
}
$\qquad$Splay
#include<bits/stdc++.h>
#define il inline
using namespace std;
il int read()
{
	int xr=0,F=1; char cr=getchar();
	while(cr<'0'||cr>'9') {if(cr=='-') F=-1;cr=getchar();}
	while(cr>='0'&&cr<='9') 
		xr=(xr<<3)+(xr<<1)+(cr^48),cr=getchar();
	return xr*F;
}
#define ls(x) tr[(x)].s[0]
#define rs(x) tr[(x)].s[1] 
const int N=1e5+5,inf=2e9;
struct tree{
	int s[2],fa,key,siz;
	tree(){s[0]=s[1]=fa=key=siz=0;}
}tr[N];
int rt,idx;
il int add(int key) {tr[++idx].key=key,tr[idx].siz=1;return idx;}
void maintain(int x) {tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1;}
void clear(int x) {tr[x].fa=tr[x].siz=tr[x].key=ls(x)=rs(x)=0;}
bool get(int x) {return x==rs(tr[x].fa);}
void rotate(int x)
{
	int y=tr[x].fa,z=tr[y].fa; bool chk=get(x); 
	if(tr[x].s[chk^1]) tr[tr[x].s[chk^1]].fa=y;
	tr[y].s[chk]=tr[x].s[chk^1];
	tr[x].s[chk^1]=y,tr[y].fa=x,tr[x].fa=z;
	if(z) tr[z].s[y==tr[z].s[1]]=x;
	maintain(y),maintain(x); 
}
void splay(int x)
{
	for(int f=tr[x].fa;f=tr[x].fa,f;rotate(x))
		if(tr[f].fa) rotate(get(x)==get(f)?f:x);
	rt=x;
}
void insert(int key)
{
	int now=rt,p=0;
	while(now) p=now,now=tr[now].s[key>tr[now].key];
	now=add(key);
	if(p) tr[p].s[key>tr[p].key]=now;
	tr[now].fa=p; splay(now);
}
void del(int key)
{
	int now=rt;
	while(now)
		if(tr[now].key==key) break;
		else now=tr[now].s[key>tr[now].key];
	if(tr[now].key!=key) return;
	splay(now);
	int cur=ls(now);while(rs(cur)) cur=rs(cur);
	tr[ls(now)].fa=0,tr[rs(now)].fa=cur;
	rs(cur)=rs(now); clear(now),splay(cur);
}
int rnk(int key)
{
	int now=rt,ans=0;
	while(now) 
		if(key>tr[now].key) ans+=tr[ls(now)].siz+1,now=rs(now);
		else now=ls(now);
	return ans;
}
int kth(int rk)
{
	int now=rt;
	while("qwq")
		if(rk<=tr[ls(now)].siz) now=ls(now);
		else if(rk==tr[ls(now)].siz+1) return splay(now),tr[now].key;
		else rk-=tr[ls(now)].siz+1,now=rs(now);
}
int pre(int key)
{
	int now=rt,res=-inf;
	while(now)
		if(tr[now].key<key) res=tr[now].key,now=rs(now);
		else now=ls(now);
	return res;
}
int nxt(int key)
{
	int now=rt,res=inf;
	while(now)
		if(tr[now].key>key) res=tr[now].key,now=ls(now);
		else now=rs(now);
	return res;
}
void debug(int x)
{
	if(!x) return;
	cout<<x<<" "<<tr[x].key<<" "<<tr[ls(x)].key<<" "<<tr[rs(x)].key<<endl;
	debug(ls(x)),debug(rs(x));
}
int main()
{
	int n=read();
	for(int i=1;i<=n;i++)
	{
		int op=read(),x=read();
		//debug(rt);
		if(op==1) insert(x);
		else if(op==2) del(x);
		else if(op==3) printf("%d\n",rnk(x));
		else if(op==4) printf("%d\n",kth(x));
		else if(op==5) printf("%d\n",pre(x));
		else printf("%d\n",nxt(x));
	}
	return 0;
}
$\qquad$Splay 区间翻转
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int inf=1e9; 
struct node{
	int fa,s[2],siz,cnt,w,v,flag;
}t[N];
int rt,tot,flag[N];
void getsiz(int x) {t[x].siz=t[t[x].s[0]].siz+t[t[x].s[1]].siz+t[x].cnt;}
int gets(int x) {return x==t[t[x].fa].s[1];}
void push_down(int x)
{
	if(t[x].s[0]) t[t[x].s[0]].flag^=1;
	if(t[x].s[1]) t[t[x].s[1]].flag^=1;
	swap(t[x].s[0],t[x].s[1]);
	t[x].flag=0;
}
void turn(int x)
{
	int y=t[x].fa,z=t[y].fa;bool chk=gets(x);
	if(t[x].s[chk^1]) t[t[x].s[chk^1]].fa=y;
	t[y].s[chk]=t[x].s[chk^1];
	t[x].s[chk^1]=y;t[y].fa=x;t[x].fa=z;
	if(z) t[z].s[y==t[z].s[1]]=x;
	getsiz(y);getsiz(x);
	//rt=x;
}
void splay(int x,int goal)
{
	for(int f=t[x].fa;f=t[x].fa,f!=goal;turn(x))
	{
		//cout<<"qwq "<<f<<endl;
		if(t[f].fa!=goal) turn(gets(x)==gets(f)?f:x);
	}
	if(goal==0) rt=x;
}
void build(int now,int l,int r)
{
	if(l>r) return;
	int mid=(l+r)>>1;
	if(mid<now) t[now].s[0]=mid;
	else t[now].s[1]=mid;
	t[mid].fa=now,t[mid].cnt=t[mid].siz=1;
	if(l==r) return;
	build(mid,l,mid-1);build(mid,mid+1,r);
	getsiz(mid);
}
int find(int k)
{
	int now=rt;
	
	while(1)
	{
		//cout<<now<<" "<<t[now].s[0]<<" "<<t[now].s[1]<<endl; 
		if(t[now].flag) push_down(now);
		if(k==t[t[now].s[0]].siz+1) return now;
		if(k<=t[t[now].s[0]].siz) now=t[now].s[0];
		else k-=t[t[now].s[0]].siz+1,now=t[now].s[1];
	}
}
void work(int l,int r)
{
	int x=find(l),y=find(r+2);
	//cout<<"find"<<endl;
	splay(x,0);
	//cout<<"splay1"<<endl;
	splay(y,x);
	//for(int i=1;i<=8;i++) cout<<t[i].fa<<" ";
	//cout<<t[y].s[0]<<endl;
	t[t[y].s[0]].flag^=1;
}
int n,m;
int main()
{
	scanf("%d%d",&n,&m);
	rt=(n+3)/2;build(rt,1,n+2);
	t[rt].fa=0;
	//for(int i=1;i<=8;i++) cout<<t[i].fa<<" ";
	for(int i=1,l,r;i<=m;i++)
	{
		scanf("%d%d",&l,&r);
		work(l,r);
	}
	for(int i=2;i<=n+1;i++) cout<<find(i)-1<<" "; 
	return 0;
}
$\qquad$FHQ Treap
#include<bits/stdc++.h>
#define ls(x) tr[(x)].l
#define rs(x) tr[(x)].r
using namespace std;
inline int read()
{
	int xr=0,F=1;char cr=getchar();
	while(cr<'0'||cr>'9') {if(cr=='-') F=-1;cr=getchar();}
	while(cr>='0'&&cr<='9')
	    xr=(xr<<3)+(xr<<1)+(cr^48),cr=getchar();
	return xr*F;
}
const int N=1e5+5;
struct node{
	int l,r,key,val;
	int siz;
}tr[N];
int rt,idx,x,y,z; 
int add(int key)
{
	tr[++idx]={0,0,key,rand(),1};
	return idx;
}
void upd(int x) {tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1;}
void split(int now,int key,int &x,int &y)
{
	if(!now) {x=y=0;return;}
	if(tr[now].key<=key) x=now,split(rs(now),key,rs(now),y);
	else y=now,split(ls(now),key,x,ls(now));
	upd(now);
}
int merge(int x,int y)
{
	if(!x||!y) return max(x,y);
	if(tr[x].val>tr[y].val) {rs(x)=merge(rs(x),y),upd(x);return x;}
	else {ls(y)=merge(x,ls(y));upd(y);return y;}
}
void ins(int key)
{
	split(rt,key,x,y);
	rt=merge(merge(x,add(key)),y);
}
void del(int key)
{
	split(rt,key,x,z),split(x,key-1,x,y);
	y=merge(ls(y),rs(y)),rt=merge(merge(x,y),z);
}
int rnk(int key)
{
	split(rt,key-1,x,y),key=tr[x].siz+1,rt=merge(x,y);
	return key;
}
int kth(int rk)
{
	int now=rt;
	while(now)
	{
		int lsiz=tr[ls(now)].siz;
		if(lsiz+1==rk) break;
		if(lsiz+1<rk) rk-=lsiz+1,now=rs(now);
		else now=ls(now);
	}
	return tr[now].key;
}
int pre(int key)
{
	split(rt,key-1,x,y);
	int now=x;
	while(rs(now)) now=rs(now);
	key=tr[now].key,rt=merge(x,y);
	return key;
}
int nxt(int key)
{
	split(rt,key,x,y);
//	for(int i=1;i<=idx;i++) 
//	{
//		cout<<tr[i].key<<" "<<tr[ls(i)].key<<" "<<tr[rs(i)].key<<endl;
//	}
	//cout<<tr[x].key<<" "<<tr[y].key<<endl;
	int now=y;
	while(ls(now)) now=ls(now);
	key=tr[now].key,rt=merge(x,y);
	return key;
}
int main()
{
	int T=read();
	while(T--)
	{
		int op=read(),x=read();
		if(op==1) ins(x);
		else if(op==2) del(x);
		else if(op==3) printf("%d\n",rnk(x));
		else if(op==4) printf("%d\n",kth(x));
		else if(op==5) printf("%d\n",pre(x));
		else printf("%d\n",nxt(x));
	}
	return 0;
}

字符串

$\qquad$Hash
const int p=131;
ull n,a[10005],ans;
string s;
ull hash(string x)
{
	int l=x.size();
	ull res=0;
	for(int i=0;i<=l;i++) res=res*p+x[i];
	return res;
}
$\qquad$KMP
#include<bits/stdc++.h>
using namespace std;
char a[1000005],b[1000005];
int nxt[1000005],n,m,j;
int main()
{
    scanf("%s%s",a+1,b+1);
    n=strlen(a+1),m=strlen(b+1);
    for(int i=2;i<=m;i++)
    {
        while(j&&b[j+1]!=b[i]) j=nxt[j];
        if(b[j+1]==b[i]) j++;
        nxt[i]=j;
    }
    j=0;
    for(int i=1;i<=n;i++)
    {
        while(j&&b[j+1]!=a[i]) j=nxt[j];
        if(b[j+1]==a[i]) j++;
        if(j==m) cout<<i-m+1<<endl;
    }
    for(int i=1;i<=m;i++)
    {
        cout<<nxt[i]<<" ";
    }
    return 0;
}
$\qquad$AC自动机
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5; 
struct node{
	int nxt,s[30],cnt;
}tr[N];
int n,T,tot,ans;
char a[N];
void build()
{
	int m=strlen(a+1),now=0;
	for(int i=1;i<=m;i++)
	{
		if(!tr[now].s[a[i]-'a']) tr[now].s[a[i]-'a']=++tot;
		now=tr[now].s[a[i]-'a'];
	}
	tr[now].cnt++;
}
void getfail()
{
	queue<int> q;
	for(int i=0;i<26;i++)
		if(tr[0].s[i]) tr[tr[0].s[i]].nxt=0,q.push(tr[0].s[i]);
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=0;i<26;i++)
		{
			if(!tr[u].s[i]) tr[u].s[i]=tr[tr[u].nxt].s[i];
			else
			{
				tr[tr[u].s[i]].nxt=tr[tr[u].nxt].s[i];
				q.push(tr[u].s[i]);
			}
		}
	}
}
void AC()
{
	int m=strlen(a+1),now=0;
	for(int i=1;i<=m;i++)
	{
		now=tr[now].s[a[i]-'a'];
		for(int t=now;t&&tr[t].cnt!=-1;t=tr[t].nxt)
		{
			ans+=tr[t].cnt;
			tr[t].cnt=-1;
		}
	}
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s",a+1);
		build();
	}
	tr[0].nxt=0;
	getfail();
	scanf("%s",a+1);
	AC();cout<<ans<<endl;
	return 0;
}
$\qquad$manacher
#include<bits/stdc++.h>
using namespace std;
const int N=2.2e7+5;
int cnt=1,r[N],mid=1,R,maxn;
char s[N],c;
int main()
{
	s[0]='~';s[1]='#';
	c=getchar();
	while(c<'a'||c>'z') c=getchar();
	while(c>='a'&&c<='z') s[++cnt]=c,s[++cnt]='#',c=getchar();
	for(int i=1;i<=cnt;i++)
	{
		if(i<R) r[i]=min(R-i+1,r[2*mid-i]);
		while(s[i-r[i]]==s[i+r[i]]) r[i]++;
		if(i+r[i]-1>=R) R=i+r[i]-1,mid=i;
		maxn=max(maxn,r[i]-1);
	}
	cout<<maxn<<endl;
	return 0;
}
$\qquad$后缀数组(SA)
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5; 
char s[N];
int n,m,sum[N],rk[N],sa[N];
int tp[N];
void qsort()
{
	for(int i=0;i<=m;i++) sum[i]=0;
	for(int i=1;i<=n;i++) sum[rk[i]]++;
	for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
	for(int i=n;i;i--) sa[sum[rk[tp[i]]]--]=tp[i];
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1),m=200;
	for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
	qsort();
	for(int w=1,tot=0;tot<n;m=tot,w<<=1)
	{
		tot=0;
		for(int i=n-w+1;i<=n;i++) tp[++tot]=i;
		for(int i=1;i<=n;i++) if(sa[i]>w) tp[++tot]=sa[i]-w;
		qsort();swap(rk,tp);
		tot=rk[sa[1]]=1;
		for(int i=2;i<=n;i++) 
			rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?tot:++tot;
	}
	for(int i=1;i<=n;i++) printf("%d ",sa[i]);
	return 0;
}
$\qquad$后缀自动机(SAM)
void add(int c)
{
	int p=lst,np=lst=++tot;f[tot]=1;
	d[np].len=d[p].len+1;
	for(;p&&!d[p].ch[c];p=d[p].fa) d[p].ch[c]=np;
	if(!p) d[np].fa=1;
	else
	{
		int q=d[p].ch[c];
		if(d[q].len==d[p].len+1) d[np].fa=q;
		else
		{
			int nq=++tot;
			d[nq]=d[q];d[nq].len=d[p].len+1;
			d[q].fa=d[np].fa=nq;
			for(;p&&d[p].ch[c]==q;p=d[p].fa) d[p].ch[c]=nq;
		}
	}
}

计算几何

$\qquad$扫描线
#include<bits/stdc++.h>
#define int long long
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=3e5+5;
int n;
struct node{
	int x,l,r,op;
}a[N];
int cnt,num,b[N],lz[N<<2];
struct node1{
	int mn,cnt,l;
}tr[N<<2];
bool cmp(node x,node y){
	return x.x<y.x;
}
void push_down(int now)
{
	tr[ls].mn+=lz[now];tr[rs].mn+=lz[now];
	lz[ls]+=lz[now];lz[rs]+=lz[now];
	lz[now]=0;
}
void build(int now,int l,int r)
{
	tr[now].l=tr[now].cnt=b[r+1]-b[l];
	if(l==r) return;
	int mid=(l+r)>>1;
	build(ls,l,mid);build(rs,mid+1,r);
}
void modify(int now,int l,int r,int ml,int mr,int op)
{
	if(l==ml&&r==mr)
	{
		//cout<<"now="<<now<<" "<<l<<" "<<r<<" "<<tr[now].cnt<<endl;
		tr[now].mn+=op;
		lz[now]+=op;
		//if(tr[now].mn==0) tr[now].cnt=tr[now].l;
		return;
	}
	int mid=(l+r)>>1;
	push_down(now);
	if(mr<=mid) modify(ls,l,mid,ml,mr,op);
	else if(ml>mid) modify(rs,mid+1,r,ml,mr,op);
	else
	{
		modify(ls,l,mid,ml,mid,op);
		modify(rs,mid+1,r,mid+1,mr,op);
	}
	tr[now].mn=min(tr[ls].mn,tr[rs].mn);
	tr[now].cnt=0;
	if(tr[ls].mn==tr[now].mn) tr[now].cnt+=tr[ls].cnt;
	if(tr[rs].mn==tr[now].mn) tr[now].cnt+=tr[rs].cnt;
	//cout<<now<<" "<<l<<" "<<r<<" "<<tr[now].cnt<<" "<<tr[ls].cnt<<" "<<tr[rs].cnt<<endl;
}
int query(int now,int l,int r,int ml,int mr)
{
	if(tr[now].mn!=0) return tr[now].l;
	else return tr[now].l-tr[now].cnt;
}
signed main()
{
	scanf("%lld",&n);
	for(int i=1,xa,xb,ya,yb;i<=n;i++)
	{
		scanf("%lld%lld%lld%lld",&xa,&ya,&xb,&yb);
		a[++cnt].x=xa,a[cnt].l=ya,a[cnt].r=yb,a[cnt].op=1;
		a[++cnt].x=xb,a[cnt].l=ya,a[cnt].r=yb,a[cnt].op=-1;
		b[++num]=ya,b[++num]=yb;
	}
	sort(b+1,b+num+1);
	int len=unique(b+1,b+num+1)-b-1;
	//cout<<len<<endl;
	for(int i=1;i<=cnt;i++)
	{
		a[i].l=lower_bound(b+1,b+len+1,a[i].l)-b;
		a[i].r=lower_bound(b+1,b+len+1,a[i].r)-b;
	}
	sort(a+1,a+cnt+1,cmp);
	build(1,1,len-1);
	int ans=0;
	for(int i=1;i<cnt;i++)
	{
		modify(1,1,len-1,a[i].l,a[i].r-1,a[i].op);
		//cout<<query(1,1,len-1,1,len-1)<<" "<<(a[i+1].x-a[i].x)<<endl;
		ans+=query(1,1,len-1,1,len-1)*(a[i+1].x-a[i].x);
	}
	cout<<ans<<endl;
	return 0;
}
$\qquad$平面最近点对
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e5+5;
typedef double db;
int n;db ans=1e18;
struct node{
	db x,y;
}a[N],t[N];
bool cmpx(node c,node d)
{
	if(c.x==d.x) return c.y<d.y;
	else return c.x<d.x;
}
bool cmpy(node c,node d){
	return c.y<d.y;
}
db dis(node c,node d){
	return (c.x-d.x)*(c.x-d.x)+(c.y-d.y)*(c.y-d.y);
}
void solve(int l,int r)
{
	if(l==r) return;
	int mid=(l+r)>>1;
	db m=a[mid].x;
	solve(l,mid);solve(mid+1,r);
	int cnt=0;
	for(int i=l;i<=r;i++)
	{
		if(a[i].x>=m-sqrt(ans)&&a[i].x<=m+sqrt(ans)) t[++cnt]=a[i];
	}
	sort(t+1,t+cnt+1,cmpy);
	for(int i=1;i<=cnt;i++)
	{
		for(int j=i+1;j<=cnt;j++)
		{
			if(t[j].y>t[i].y+sqrt(ans)) break;
			ans=min(ans,dis(t[j],t[i]));
		}
	}
}
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmpx);
	solve(1,n);
	cout<<(long long)ans<<endl;
	return 0;
}
$\qquad$全家桶
typedef double db;
const db eps=1e-10;
struct V{
	db x,y;
};
#define il inline
/*向量之间运算*/ 
il bool operator ==(const V &a,const V &b) {return fabs(a.x-b.x)<=eps&&fabs(a.y-b.y)<=eps;}  
il bool operator !=(const V &a,const V &b) {return !(a==b);}

il V operator +(const V &a,const V &b) {return {a.x+b.x,a.y+b.y};}
il V operator -(const V &a,const V &b) {return {a.x-b.x,a.y-b.y};}
il V operator *(const V &a,const db &x) {return {a.x*x,a.y*x};}
il V operator *(const db &x,const V &a) {return {a.x*x,a.y*x};}
il V operator /(const V &a,const db &x) {return {a.x/x,a.y/x};}

il db operator *(const V &a,const V &b) {return a.x*b.x+a.y*b.y;} 
il db operator ^(const V &a,const V &b) {return a.x*b.y-a.y*b.x;}

il db len(const V &a) {return sqrt(a*a);}
il V  mid(const V &a,const V &b) {return {(a.x+b.x)/2,(a.y+b.y)/2};}
il V  cui(const V &a) {return {a.y,-a.x};}
il V   dw(const V &a) {return a/len(a);}

/*角度*/
il db tri_S(const V &a,const V &b,const V &c) {return fabs((a-c)^(b-c))/2;}
il db angle(const V &a,const V &b) {return acos(a*b/len(a)/len(b));}
//以下均为角 BAC. 
il bool zhi(const V &a,const V &v,const V &c) {return fabs((b-a)*(c-a))<=eps;} 
il bool dun(const V &a,const V &b,const V &c) {return (b-a)*(c-a)<-eps;}
il bool rui(const V &a,const V &b,const V &c) {return (b-a)*(c-a)>eps;}
il V turn(const V &a,db t){
	db s=sin(t),c=cos(t);
	return {a.x*c-a.y*s,a.x*s+a.y*c};
}

/*线*/
struct line{
	V d,a,b;
};
inline line trans(db a,db b,db c,db d)
{
	V dd={c-a,d-b},x={a,b},y={c,d};
	dd=dw(dd);
	return {dd,x,y};
}
inline line trans(const V &a,const V &b)
{
	V dd={b.x-a.x,b.y-a.y};dd=dw(dd);
	return {dd,a,b};
}

/*点和线的关系*/
il V cui(const V &o,const line &l) {return ((o-l.a)*l.d)*l.d+l.a;}
il V duichen(const V &o,const line &l)
{
	V qwq=cui(o,l);
	return {2*qwq.x-o.x,2*qwq.y-o.y};
}
il db dis(const V &o,const line &l,int op=0)
{
	if(op&&(dun(l.a,o,l.b)||dun(l.b,o,l.a))) return min(len(l.a-o),len(l.b-o));
	else return fabs((l.a-o)^(l.b-o))/len(l.b-l.a);
}
il bool on_line(const line &l,const V &o) {return fabs((o-l.a)^(l.b-l.a))<eps;}
il bool on_seg(const line &l,const V &o) {return fabs(len(o-l.a)+len(o-l.b)-len(l.b-l.a))<eps;}
il int pos(const line &l,const V &o)
{
	if(!on_line(l,o)) 
	{
		if((o-l.a)^l.d<-eps) return 1;//clockwise
		else return 2;//counter clockwise
	}
	if((o-l.a)*(o-l.b)<-eps) return 5;//on
	else if(len(o-l.a)>len(o-l.b)) return 3;//front
	else return 4;//back
}

/*线和线*/
//线和线
il bool gongxian(const line &a,const line &b) {return fabs(a.d^b.d)<eps;}
il bool cuizhi  (const line &a,const line &b) {return fabs(a.d*b.d)<eps;} 
il bool xdjiao(const line &u,const line &v)//拼音太长缩写了>_< 
{
	if(min(u.a.x,u.b.x)>max(v.a.x,v.b.x)+eps||max(u.a.x,u.b.x)<min(v.a.x,v.b.x)-eps) return 0;
	if(min(u.a.y,u.b.y)>max(v.a.y,v.b.y)+eps||max(u.a.y,u.b.y)<min(v.a.y,v.b.y)-eps) return 0;
	return ((u.a-v.a)^v.d)*((u.b-v.a)^v.d)<eps&&((v.a-u.a)^u.d)*((v.b-u.a)^u.d)<eps;
}
il V jiaodian(const line &u,const line &v)
{
	double k=((v.a-u.a)^v.d)/(u.d^v.d);
	return k*u.d+u.a;
}
il line pingfen(const V &a,const V &b,const V &c)//角 BAC 
{
	int d1=dw(b-a),d2=dw(c-a);
	int d=(d1+d2)/2;
	return (line){d,a,a+d};
}

/*多边形*/
il int in_poly(V *a,int n,V o)
{
	int res=0;a[n+1]=a[1];
	for(int i=1;i<=n;i++)
	{
		V u=a[i],v=a[i+1];
		if(on_seg(trans(u,v),o)) return 1;
		if(abs(u.y-v.y)<eps) continue;
		if(max(u.y,v.y)<o.y-eps) continue;
		if(min(u.y,v.y)>o.y-eps) continue;
		double x=u.x+(o.y-u.y)/(v.y-u.y)*(v.x-u.x);
		if(x<o.x) res^=1;
	}
	return res?2:0;
}
il double S(V *a,int n)
{
	db res=0;
	for(int i=1;i<=n;i++) res+=(a[i]^a[i%n+1]);
	return res/2;
}
il int is_convex(V *a,int n)
{
	a[0]=a[n],a[n+1]=a[1];
	int op=0;
	for(int i=1;i<=n;i++)
	{
		V x=a[i]-a[i-1],y=a[i+1]-a[i];
		if(abs(x^y)<eps) continue;
		int np=((x^y)>0)?1:-1;
		if(!op) op=np;
		else if(op!=np) return 0;
	}
	return 1;
}

/*凸包*/
V Q[N];int tp;
bool cmp(V a,V b)
{
	if(a.x==b.x) return a.y<b.y;
	else return a.x<b.x;
}
void andrew(V *a,int n)
{
	sort(a+1,a+n+1,cmp);
	Q[++tp]=a[1];
	for(int i=2;i<=n;Q[++tp]=a[i],i++)
		while(tp>1&&((Q[tp]-Q[tp-1])^(a[i]-Q[tp]))<eps) tp--;
	int pos=tp;
	for(int i=n-1;i;Q[++tp]=a[i],i--)
		while(tp>pos&&((Q[tp]-Q[tp-1])^(a[i]-Q[tp]))<eps) tp--;
	tp--;
}

/*旋转卡壳*/
int ans;
void find()
{
    int now=2;
    for(int i=1;i<=tp;i++)
    {
        V a=Q[i],b=Q[i%tp+1];
        while(Dis(a,b,Q[now%tp+1])>Dis(a,b,Q[now])) now=now%tp+1;
        ans=max(ans,dis(a,Q[now]));
        ans=max(ans,dis(b,Q[now]));
    }
}

/*半平面交*/
struct line
{
	V a,b,d;
	double angle;
}a[N];
line trans(V a,V b) 
{
	double res=atan2((b-a).y,(b-a).x);V d=(b-a)/len(b-a);
	return {a,b,d,res};
}
V jiaodian(line a,line b)
{
	double k=((b.a-a.a)^(b.d))/(a.d^b.d);
	return a.a+(k*a.d);
}
bool cmp(line x,line y)
{
	if(fabs(x.angle-y.angle)>eps) return x.angle<y.angle;
	else return ((y.a-x.a)^(y.b-x.a))>eps;
}
bool check(line a,line b,line c)
{
	V p=jiaodian(b,c);
	return (a.d^(p-a.a))<-eps;
}
line Q[N];
int h=1,t=0,tot;
V ans[N];
void solve()
{
	sort(a+1,a+tot+1,cmp);
	int cnt=1;
	for(int i=2;i<=tot;i++)
		if(fabs(a[i].angle-a[i-1].angle)>eps) a[++cnt]=a[i];
	tot=cnt;
	
	Q[++t]=a[1],Q[++t]=a[2];
	for(int i=3;i<=tot;i++)
	{
		while(h<t&&check(a[i],Q[t],Q[t-1])) t--;
		while(h<t&&check(a[i],Q[h],Q[h+1])) h++;
		Q[++t]=a[i];
	}
	while(h<t&&check(Q[h],Q[t],Q[t-1])) t--;
	while(h<t&&check(Q[t],Q[h],Q[h+1])) h++;
	int qwq=0;
	for(int i=h;i<t;i++) ans[++qwq]=jiaodian(Q[i],Q[i+1]);
	if(t-h>1) ans[++qwq]=jiaodian(Q[h],Q[t]);
	tot=qwq;
}
int main()
{
	int n=read();tot=0;
	for(int i=1;i<=n;i++)
	{
		int m=read();
		for(int j=1;j<=m;j++)
			b[j].x=read(),b[j].y=read();
		for(int j=1;j<=m;j++) a[++tot]=trans(b[j],b[j%m+1]);
	}
	solve();
	double res=0;
	for(int i=1;i<=tot;i++) res+=(ans[i]^ans[i%tot+1]);
	printf("%.3lf\n",res/2);
	return 0;
}

更新日志

  • 2020/4/19 一代初稿
  • 2021/1/29 二代初稿(暴露了 yx 初中时代的科技树
  • 2022/8/15 几乎重构了整篇文章。
  • 2023/2/14 重构了一些数据结构板子。

博客长了修改起来很卡(截至 1.8 的 markdown 源码有 2593 行),可能不会经常更新。
感谢 ncwzdlsd 大佬教会窝怎么缩进ww 先咕了,有空再加上(

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值