此处用于存放本喵的 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&∑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;
}
更新日志
博客长了修改起来很卡(截至 1.8 的 markdown 源码有 2593 行),可能不会经常更新。
感谢 ncwzdlsd 大佬教会窝怎么缩进ww 先咕了,有空再加上(