常用模板(十分不全)
模板
常用技巧
快读(慢写)
#include<iostream>
using namespace std;
int read(){
char ch=getchar();
int res=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) res=(res<<1)+(res<<3)+ch-48,ch=getchar();
return res;
}
void print(int x){
if(x/10) print(x/10);
putchar(x%10+'0');
}
int main(){
int n;
n=read();
print(n);
}
离散化
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
int newn=unique(b+1,b+1+n)-(b+1);
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+1+newn,a[i])-b;
}
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
}
图论部分
欧拉回路
#include<iostream>
#include<cstdio>
using namespace std;
int A[501][501];
int n;
int B[501];
void dfs(int i){
printf("%d\n",i);
for(int j=1;j<=500;j++){
if(A[i][j]>=1){
A[i][j]--;
A[j][i]--;
dfs(j);
}
}
}
int main(){
int a,b,start=1;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
A[a][b]+=1;
A[b][a]+=1;
B[a]++;
B[b]++;
}
for(int i=1;i<=500;i++){
if(B[i]%2==1) {
start=i;
break;
}
}
dfs(start);
}
最短路
floyd
码风突变,因为是一本通粘的
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int a[101][3];
double f[101][101];
int n,i,j,k,x,y,m,s,e;
int main()
{
cin >> n;
for (i = 1; i <= n; i++)
cin >> a[i][1] >> a[i][2];
cin >> m;
memset(f,0x7f,sizeof(f)); //初始化f数组为最大值
for (i = 1; i <= m; i++) //预处理出x、y间距离
{
cin >> x >> y;
f[y][x] = f[x][y] = sqrt(pow(double(a[x][1]-a[y][1]),2) +pow(double(a[x][2]-a[y][2]),2));
//pow(x,y)表示x^y,其中x,y必须为double类型,要用cmath库
}
cin >> s >> e;
for (k = 1; k <= n; k++) //floyed 最短路算法
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
if ((i!=j) && (i!=k) && (j!=k) && (f[i][k]+f[k][j]<f[i][j]))
f[i][j] = f[i][k] + f[k][j];
printf("%.2lf\n",f[s][e]);
return 0;
}
spfa
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
struct Node{
int next,to,w;
}edge[100001];
int head[1001],cnt,dis[1001],c[100001][4];
bool vis[1001];
void Add(int u,int v,int w){
edge[++cnt].next=head[u];
edge[cnt].to=v;
edge[cnt].w=w;
head[u]=cnt;
}
void spfa(int x){
memset(dis,0x3f,sizeof(dis));
queue <int> que;
que.push(x);
vis[x]=1;
dis[x]=0;
while(!que.empty()){
int k=que.front();
que.pop();
vis[k]=0;
for(int i=head[k];i!=0;i=edge[i].next){
int j=edge[i].to;
if(dis[j]>dis[k]+edge[i].w){
dis[j]=dis[k]+edge[i].w;
if(!vis[j]){
vis[j]=1;
que.push(j);
}
}
}
}
}
//void dij(int x)
int main(){
int h,x,y,z;
scanf("%d%d%d",&n,&m,&h);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z);
c[i][1]=x;
c[i][2]=y;
c[i][3]=z;
}
spfa(h);
int k[n+1];
for(int i=1;i<=n;i++){
k[i]=dis[i];
}
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
cnt=0;
for(int i=1;i<=m;i++){
Add(c[i][2],c[i][1],c[i][3]);
}
spfa(h);
int maxn=0;
for(int i=1;i<=n;i++){
if(k[i]+dis[i]>maxn) maxn=k[i]+dis[i];
}
printf("%d",maxn);
return 0;
}
dij
#include<bits/stdc++.h>
using namespace std;
int n,m;
double dis[1001],f[1001][1001];
int x[5],y[5];
pair <int,int> g[1001];
bool vis[1001];
void Add1(int i,int j,int a,int b,int w){
f[b][a]=f[a][b]=sqrt((double)(x[i]-x[j])*(double)(x[i]-x[j])+(double)(y[i]-y[j])*(double)(y[i]-y[j])) * w;
}
void Add2(int x1,int y1,int i,int a,int b,int w){
f[b][a]=f[a][b]=sqrt((double)(x[i]-x1)*(double)(x[i]-x1)+(double)(y[i]-y1)*(double)(y[i]-y1)) * w;
}
void dij(int x){
memset(dis,127,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[x]=0;
priority_queue < pair <int,int> > que;
que.push(make_pair(0,x));
while(que.size()){
int k=que.top().second;
que.pop();
if(vis[k]) continue;
vis[k]=1;
for(int i=1;i<=n*4;i++){
if(dis[i]>dis[k]+f[k][i]){
dis[i]=dis[k]+f[k][i];
que.push(make_pair(-dis[i],i));
}
}
}
}
int main(){
int start,end;
double w,plane;
scanf("%d",&m);
for(int k=1;k<=m;k++){
memset(f,127,sizeof(f));
scanf("%d%lf%d%d",&n,&plane,&start,&end);
for(int i=1;i<=n;i++){
x[4]=0,y[4]=0;
for(int j=1;j<=3;j++) {
scanf("%d%d",&x[j],&y[j]);
}
int k1=0,k2=0,k3=0;
for(int i1=1;i1<=3;i1++){
for(int j=i1+1;j<=3;j++){
int l=6-i1-j;
if(abs((y[i1]-y[l])*(y[j]-y[l]))==abs((x[i1]-x[l])*(x[j]-x[l]))){
k1=i1,k2=j,k3=l;
}
}
}
x[4]=x[k1]+x[k2]-x[k3];
y[4]=y[k1]+y[k2]-y[k3];
for(int j=1;j<=4;j++)
for(int h=1;h<=i*4-4;h++){
Add2(g[h].first,g[h].second,j,i*4-4+j,h,plane);
}
scanf("%lf",&w);
for(int j=1;j<=4;j++){
g[i*4-4+j]=make_pair(x[j],y[j]);
for(int l=j+1;l<=4;l++){
Add1(j,l,4*i-4+j,4*i-4+l,w);
}
}
}
double minl=0x7f7f7f7f;
for(int i=1;i<=4;i++){
dij(4*start+i-4);
for(int j=1;j<=4;j++){
minl=min(minl,dis[4*end-4+j]);
}
}
printf("%.1lf\n",minl);
}
return 0;
}
并查集
#include<iostream>
using namespace std;
int f[20001];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
f=ch!='-';
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return f?x:-x;
}
int find(int x){
while(f[x]!=x) x=f[x];
return x;
}
int main(){
int n,m;
n=read();
m=read();
int x,y;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++){
x=read();
y=read();
x=find(x);
y=find(y);
if(x!=y) f[y]=x;
}
n=read();
for(int i=1;i<=n;i++){
x=read();
y=read();
if(find(x)==find(y)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
权值并查集
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int f[50001],g[50001]/*Óëֱϵ¸¸ÇפιØϵ(½üºõµÈ¼ÛÓë¸ù......)*/;
int find(int x){
int fa=f[x];
if(x!=fa){
f[x]=find(fa);
g[x]=(g[x]+g[fa])%3;
return f[x];
}
else return fa;
}
int main(){
for(int i=1;i<=50000;i++) f[i]=i;
int n,x,y,z,sum=0,k;
cin>>n>>k;
for(int i=1;i<=k;i++){
cin>>z>>x>>y;
if(x>n||y>n){
sum++;
continue;
}
int xx=find(x),yy=find(y);
if(z==1){
if(xx==yy&&g[x]!=g[y]){
sum++;
continue;
}
else if(xx!=yy){
f[xx]=yy;
g[xx]=(g[y]-g[x]+3)%3;
}
}
if(z==2){
if(x==y){
sum++;
continue;
}
int l=(g[x]-g[y]+3)%3;
if(l!=1&&xx==yy){
sum++;
continue;
}
else if(xx!=yy){
f[xx]=yy;
g[xx]=(1+g[y]-g[x]+3)%3;
}
}
}
cout<<sum<<endl;
}
种类并查集
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int f[200000],n;
int find(int x){
if(f[x]!=x){
x=find(f[x]);
}
return f[x];
}
void add(int x,int y){
int xx=find(x);
int yy=find(y);
f[yy]=xx;
}
int main(){
int sum=0,k,x,y,z;
cin>>n>>k;
for(int i=0;i<200000;i++){
f[i]=i;
}
for(int i=1;i<=k;i++){
scanf("%d%d%d",&z,&x,&y);
if(x>n||y>n){
sum++;
continue;
}
if(z==1){
if(x==y) continue;
if(find(x)==find(y+2*n)||find(y)==find(x+2*n)){
sum++;
continue;
}
add(x,y);//同
add(x+n,y+n);
add(x+2*n,y+2*n);
}
if(z==2){
if(x==y){
sum++;
continue;
}
if(find(n+x)==find(y)||find(x)==find(y)){
sum++;
continue;
}
add(x,n+y);
add(2*n+x,y);
add(x+n,y+2*n);
}
}
cout<<sum;
}
最小生成树
prim
#include<iostream>
#include<cstring>
using namespace std;
int n,m;
int main(){
int l,y,z,s=0;
cin>>n>>m;
int v[n+1][n+1];
memset(v,0x3f,sizeof(v));
for(int i=1;i<=m;i++){
cin>>l>>y>>z;
v[l][y]=z;
v[y][l]=z;
s+=z;
}
int x=1;
int dis[n+1],sum=0;
for(int i=1;i<=n;i++) dis[i]=v[i][x];
dis[x]=0;
for(int k=1;k<=n-1;k++){
int min=0x7f7f7f7f,g=0;
for(int i=1;i<=n;i++){
if(dis[i] && dis[i]<min){
min=dis[i];
g=i;
}
}
sum+=dis[g];
dis[g]=0;
for(int i=1;i<=n;i++){
if(dis[i]>v[i][g]) dis[i]=v[i][g];
}
}
cout<<s-sum;
return 0;
}
kruskal
#include<iostream>
#include<algorithm>
using namespace std;
int cnt=0,sum=0,f[2001],n,cn=1;
struct Node{
int from,to,w;
bool operator < (const Node &A) const {
return w < A.w;
}
}edge[10001];
void Add(int x,int y,int z){
edge[++cnt].from=x;
edge[cnt].to=y;
edge[cnt].w=z;
}
int find(int x){
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
void kruskal(){
int k=1;
while(cn<=n-1){
int x=find(edge[k].from);
int y=find(edge[k].to);
if(x!=y){
f[x]=y;
sum+=edge[k].w;
cn++;
}
k++;
}
}
int main(){
int m,x,y,z,sum1=0,k;
cin>>n>>m;
for(int i=1;i<=2000;i++) f[i]=i;
for(int i=1;i<=m;i++){
cin>>k>>x>>y>>z;
if(k==1){
int xx=find(x);
int yy=find(y);
if(xx!=yy){
f[xx]=yy;
cn++;
}
sum+=z;
}
Add(x,y,z);
}
sort(edge+1,edge+1+cnt);
kruskal();
cout<<sum;
}
拓扑排序
#include<iostream>
using namespace std;
#define N 1001
struct Node{
int to,next,w;
}edge[20001];
int head[N],cnt=0,n,m,r[N],l[N],c[N],U[N],C[N];
bool Technology[N];
void add(int x,int y,int z){
edge[++cnt].next = head[x];
edge[cnt].to = y;
edge[cnt].w = z;
head[x]=cnt;
r[y]++;
c[x]++;
}
void nao(){
for(int i=1,cn;i<=n;i++){
cn=0;
bool a=false;
for(int j=1;j<=n;j++)
if(r[j]==0){
r[j]=100000;
a=true;
l[++cn]=j;
}
for(int j=1;j<=cn;j++)
for(int g=head[l[j]];g;g=edge[g].next) {
r[edge[g].to]--;
if(C[l[j]]>0){
if(!Technology[edge[g].to]) C[edge[g].to]-=U[edge[g].to];
C[edge[g].to]+=edge[g].w*C[l[j]];
Technology[edge[g].to]=1;
}
}
}
}
int main(){
int x,y,z;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>C[i]>>U[i];
}
for(int i=1;i<=m;i++){
cin>>x>>y>>z;
add(x,y,z);
}
nao();
bool h=0;
for(int i=1;i<=n;i++){
if(c[i]==0){
if(C[i]>0){
cout<<i<<" "<<C[i]<<endl;
h=1;
}
}
}
if(!h) cout<<"NULL";
return 0;
}
差分约束
#include<iostream>
#include<cstring>
using namespace std;
const int M=1e7+10,N=1e5+10;
struct Node{
int next,to,w;
}e[M];
bool vis[N];
int dis[N],head[N],cnt,n,m;
void add(int u,int v,int w){
e[++cnt].next=head[u];
e[cnt].to=v;
e[cnt].w=w;
head[u]=cnt;
}
void spfa(int x){
vis[x]=1;
for(int i=head[x];i;i=e[i].next){
if(dis[e[i].to]<dis[x]+e[i].w){
dis[e[i].to]=dis[x]+e[i].w;
if(vis[e[i].to]) {
printf("No");
exit(0);
}
spfa(e[i].to);
}
}
vis[x]=0;
}
int main(){
cin>>n>>m;
int x,y,z,w;
for(int i=1;i<=m;i++){
cin>>z;
if(z==1){
cin>>x>>y>>w;
add(y,x,-w);
}
if(z==2){
cin>>x>>y>>w;
add(x,y,w);
}
if(z==3){
cin>>x>>y;
add(x,y,0);
add(y,x,0);
}
}
for(int i=1;i<=n;i++) add(0,i,0);
memset(dis,-0x3f,sizeof(dis));
dis[0]=0;
spfa(0);
cout<<"Yes";
return 0;
}
tarjan
1. 强连通分量
#include<iostream>
#include<stack>
using namespace std;
const int N=1e6+10;
int cnt,head[N],num,dfn[N],low[N],t,Num[N];
bool vis[N];
struct Node{
int nxt,to;
}e[N];
void Add(int u,int v){
e[++cnt]={head[u],v};
head[u]=cnt;
}
stack <int> sta;
void tarjan(int x){
dfn[x]=low[x]=++num;
sta.push(x);
vis[x]=1;
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(!dfn[to]){
tarjan(to);
low[x]=min(low[x],low[to]);
}
else if(vis[to]) low[x]=min(low[x],dfn[to]);
}
if(dfn[x]==low[x]){
t++;
int y;
do{
y=sta.top();
sta.pop();
vis[y]=0;
Num[t]++;
}while(x!=y);
}
}
int main(){
int n,x;
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
Add(i,x);
Add(0,i);
}
tarjan(0);
int minl=0x3f3f3f3f;
for(int i=1;i<=t;i++){
if(Num[i]>=2) minl=min(minl,Num[i]);
}
cout<<minl;
}
2. 求割点
#include<iostream>
using namespace std;
const int N=1e5+1;
int p[N],head[N],cnt,root,step,dfn[N],low[N];
bool cut[N];
struct Node{
int nxt,to;
}e[N];
void add(int x,int y){
e[++cnt]={head[x],y};
head[x]=cnt;
}
void tarjan(int x,int fa){
dfn[x]=low[x]=++step;
int son=0;
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(!dfn[to]){
son++;
tarjan(to,x);
low[x]=min(low[x],low[to]);
if(low[to]>=dfn[x]){
if(x!=fa || son>1) cut[x]=1;
}
}
else low[x]=min(low[x],dfn[to]);
}
}
int main(){
int n,x,y;
cin>>n;
while(cin>>x){
cin>>y;
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) {
tarjan(i,i);
}
}
int sum=0;
for(int i=1;i<=n;i++){
if(cut[i]){
sum++;
}
}
cout<<sum<<endl;
for(int i=1;i<=n;i++) if(cut[i]) cout<<i<<endl;
}
3. 求桥(割边)
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e6+100;
int head[N],low[N],dfn[N],p[N],cnt,step;
bool g[N];
struct Node{
int nxt,to,id;
}e[N];
void add(int x,int y,int z){
e[++cnt]={head[x],y,z};
head[x]=cnt;
}
void tarjan(int x){
dfn[x]=low[x]=++step;
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(!dfn[to]){
p[to]=e[i].id;
tarjan(to);
low[x]=min(low[x],low[to]);
}
else if(e[i].id!=p[x]) low[x]=min(low[x],dfn[to]);
}
if(p[x] && dfn[x]==low[x]) g[p[x]]=1;
}
int main(){
int n;
while(cin>>n){
memset(g,0,sizeof(g));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(e,0,sizeof(e));
memset(head,0,sizeof(head));
cnt=0;
int m,qwq=0;
cin>>m;
if(n==0) continue;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
qwq++;
add(x,y,qwq);
add(y,x,qwq);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) tarjan(i);
}
int sum=0;
for(int i=1;i<=cnt;i++){
if(g[e[i].id]) {
g[e[i].id]=0;
sum++;
}
}
cout<<sum<<endl;
}
}
倍增LCA
#include<iostream>
#include<cmath>
using namespace std;
int dp[1001][101],deep[1001],cnt,head[1001],n;
struct Node{
int nxt,to;
}e[114514];
void add(int x,int y){
e[++cnt]={head[x],y};
head[x]=cnt;
}
void dfs(int x,int fa){
deep[x]=deep[fa]+1;
dp[x][0]=fa;
for(int j=1;(1<<j)<=deep[x];j++){
dp[x][j]=dp[dp[x][j-1]][j-1];
}
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(to!=fa) dfs(to,x);
}
}
int lca(int u,int v){
int deepu=deep[u],deepv=deep[v];
if(deepu!=deepv){
if(deepu<deepv){
swap(deepu,deepv);
swap(u,v);
}
int d=deepu-deepv;
for(int i=0;i<=log2(n)+1;i++){
if((1<<i)&d) u=dp[u][i];
}
}
if(u==v) return u;
for(int i=log2(n)+1;i>=0;i--){
if(deep[dp[u][i]]<=0) continue;
if(dp[u][i]==dp[v][i]) continue;
else v=dp[v][i],u=dp[u][i];
}
return dp[u][0];
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
}
int x,y;
cin>>x>>y;
dfs(1,1);
cout<<lca(x,y);
}
二分图匹配
#include<iostream>
using namespace std;
int col[100001],cnt,head[100001];
struct Star{
int nxt,to;
}e[1000001];
void add(int u,int v){
e[++cnt]={head[u],v};
head[u]=cnt;
}
bool dfs(int x,int fa,int color){
col[x]=color;
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(to==fa) continue;
if(col[to]==0 && (!dfs(to,x,3-color))) return false;//如果未染色,但染色失败,返回false
if(col[to]==color) return false;//如果染色,但颜色相同,这说明相同颜色相通,不符合定义
}
return true;
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,m;
bool flag=true;
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
add(x,y);add(y,x);
}
for(int i=1;i<=n;i++){//用于处理不联通的情况
if(!col[i]){
if(!dfs(i,0,1)){
flag=false;
break;
}
}
}
if(flag) cout<<"Yes";
else cout<<"No";
}
匈牙利算法
#include<iostream>
#include<cstring>
using namespace std;
int cnt,head[100001],match[100001]/*右方点的匹配*/;
int n_le/*左边的点数*/,n_ri/*右边的点数*/,m;
bool vis[100001];//右方点是否匹配
struct Star{
int nxt,to;
}e[1000001];
void add(int u,int v){
e[++cnt]={head[u],v};
head[u]=cnt;
}
bool Match(int x){
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(!vis[to]){
vis[to]=true;
if((!match[to]) || Match(match[to])){
match[to]=x;//改嫁(换色)
return true;
}
}
}
return false;
}
int Hungarian(){
int ans_Hungarian=0;
for(int i=1;i<=n_le;i++){
memset(vis,0,sizeof(vis));
if(Match(i)){
ans_Hungarian++;
}
}
return ans_Hungarian;
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n_le>>n_ri>>m;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
add(x,y);add(y,x);
}
cout<<Hungarian();
}
树相关
重链剖分
#include<bits/stdc++.h>
using namespace std;
#define lid id<<1
#define rid id<<1|1
// #define int long long
const int N=1e6+10;
int timer,head[N],cnt;
int son[N],dfn[N],deep[N],siz[N],f[N],top[N],cnin[N],a[N];
struct Star{
int nxt,to;
}e[N];
struct Tree{
int l,r,maxn,sum,lazy;
}d[4*N];
void PushUp(int id){
d[id].sum=d[lid].sum+d[rid].sum;
d[id].maxn=max(d[lid].maxn,d[rid].maxn);
}
void Build(int id,int l,int r){
d[id].l=l;
d[id].r=r;
if(l==r){
d[id].sum=a[l];
d[id].maxn=a[l];
return;
}
int mid=(l+r)>>1;
Build(lid,l,mid);
Build(rid,mid+1,r);
PushUp(id);
}
void Update(int id,int pos,int w){
if(d[id].l==d[id].r){
d[id].sum=w;
d[id].maxn=w;
return;
}
if(pos<=d[lid].r) Update(lid,pos,w);
else Update(rid,pos,w);
PushUp(id);
}
int Get_Sum(int id,int l,int r){
if(l<=d[id].l && d[id].r<=r) return d[id].sum;
int sum=0;
if(l<=d[lid].r) sum=Get_Sum(lid,l,r);
if(r>d[lid].r) sum+=Get_Sum(rid,l,r);
return sum;
}
int Get_Max(int id,int l,int r){
if(l<=d[id].l && d[id].r<=r) return d[id].maxn;
int maxn=-INT_MAX;
if(l<=d[lid].r) maxn=Get_Max(lid,l,r);
if(r>d[lid].r) maxn=max(maxn,Get_Max(rid,l,r));
return maxn;
}
void add(int u,int v){
e[++cnt]={head[u],v};
head[u]=cnt;
}
void dfs1(int x,int fa){//初始化size,father,deep,son
siz[x]=1;
f[x]=fa;
deep[x]=deep[fa]+1;
int max_size=0;
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(deep[to]) continue;
dfs1(to,x);
siz[x]+=siz[to];
if(siz[to]>max_size){
max_size=siz[to];
son[x]=to;
}
}
}
void dfs2(int x,int fa){//维护dfn,top,rak
dfn[x]=++timer;
top[x]=fa;
a[dfn[x]]=cnin[x];
if(son[x]){
dfs2(son[x],fa);
}
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if((to==son[x]) || (to==f[x])) continue;
dfs2(to,to);
}
}
int Query_Sum(int x,int y){
int sum=0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]]) swap(x,y);
sum+=Get_Sum(1,dfn[top[x]],dfn[x]);
x=f[top[x]];
}
if(deep[x]>deep[y]) swap(x,y);
sum+=Get_Sum(1,dfn[x],dfn[y]);
return sum;
}
int Query_Max(int x,int y){
int maxn=-INT_MAX;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]]) swap(x,y);
maxn=max(maxn,Get_Max(1,dfn[top[x]],dfn[x]));
x=f[top[x]];
}
if(deep[x]>deep[y]) swap(x,y);
maxn=max(maxn,Get_Max(1,dfn[x],dfn[y]));
return maxn;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,m;
cin>>n;
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++) cin>>cnin[i];
dfs1(1,0);
dfs2(1,1);
Build(1,1,timer);
cin>>m;
for(int i=1;i<=m;i++){
string op;
int x,y;
cin>>op>>x>>y;
if(op=="QMAX"){
cout<<Query_Max(x,y)<<"\n";
}
if(op=="QSUM"){
cout<<Query_Sum(x,y)<<"\n";
}
if(op=="CHANGE"){
Update(1,dfn[x],y);
}
}
}
虚树
// 双排序维护
#include<bits/stdc++.h>
using namespace std;
#define re register
#define int long long
#define endl '\n'
const int N=6e5+10;
inline int max(int x,int y){return (x<y)?y:x;}
inline int min(int x,int y){return (x<y)?x:y;}
struct Node{
int nxt,to,w;
}e[N];
int head[N],cntt;
int f[N][31],mindis[N][31],dep[N],dfn[N],timer;
void add(int x,int y,int w){
e[++cntt]={head[x],y,w};
head[x]=cntt;
}
void dfs(int x,int fa){
for(int i=1;i<=30;i++){
mindis[x][i]=0x3f3f3f3f3f3f3f3f;
}
dep[x]=dep[fa]+1;
f[x][0]=fa;
dfn[x]=++timer;
for(int i=1;i<=30;i++){
f[x][i]=f[f[x][i-1]][i-1];
mindis[x][i]=min(mindis[x][i-1],mindis[f[x][i-1]][i-1]);
}
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(to==fa) continue;
mindis[to][0]=e[i].w;
dfs(to,x);
}
head[x]=0;
}
int dis;
int Lca(int u,int v){
dis=0x3f3f3f3f3f3f3f3f;
if(dep[u]!=dep[v]){
int deepu=dep[u],deepv=dep[v];
if(deepu<deepv){
swap(u,v);
swap(deepu,deepv);
}
int d=deepu-deepv;
for(int i=0;i<=20;i++){
if(d&(1<<i)){
dis=min(dis,mindis[u][i]);
u=f[u][i];
}
}
}
if(u==v) return u;
for(int i=20;i>=0;i--){
if(dep[u]<=0) continue;
if(f[u][i]!=f[v][i]){
dis=min(dis,min(mindis[u][i],mindis[v][i]));
u=f[u][i],v=f[v][i];
}
}
dis=min(dis,min(mindis[u][0],mindis[v][0]));
return f[u][0];
}
int dp[N];
bool import[N];
void dfs_ans(int x){
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to,w=e[i].w;
if(to==f[x][0]) continue;
dfs_ans(to);
if(import[to]) dp[x]+=w;
else dp[x]+=min(dp[to],w);
}
}
void dfs_cut(int x){
for(auto i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(to==f[x][0]) continue;
dfs_cut(to);
}
head[x]=0;
dp[x]=0;
}
int point[N];
bool cmp(int a,int b){
return dfn[a]<dfn[b];
}
int a[N];
void Build(int cnt){
cntt=0;
int len=0;
sort(point+1,point+1+cnt,cmp);
for(int i=1;i<cnt;i++){
a[++len]=point[i];
a[++len]=Lca(point[i],point[i+1]);
// cerr<<point[i]<<'&'<<point[i+1]<<" : "<<Lca(point[i],point[i+1])<<"qwq\n";
}
a[++len]=point[cnt];
sort(a+1,a+1+len,cmp);
len=unique(a+1,a+1+len)-a-1;
for(int i=1,lca;i<len;i++){
lca=Lca(a[i],a[i+1]);
Lca(lca,a[i+1]);
add(lca,a[i+1],dis);
// cerr<<a[i]<<" & "<<a[i+1]<<"->"<<lca<<" : "<<dis<<"awa\n";
}
}
signed main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n;
cin>>n;
int x,y,z;
for(int i=1;i<n;i++){
cin>>x>>y>>z;
add(x,y,z);
add(y,x,z);
}
dfs(1,0);
int m,k,h;
cin>>m;
for(int i=1;i<=m;i++){
cin>>k;
for(int j=1;j<=k;j++){
cin>>h;
point[j]=h;
import[h]=1;
}
point[++k]=1;
Build(k);
// cerr<<head[1]<<'.';
dfs_ans(1);
cout<<dp[1]<<'\n';
for(int j=1;j<=k;j++){
import[point[j]]=0;
}
dfs_cut(1);
}
return 0;
}
数论部分
高斯消元
#include<iostream>
#include<cmath>
#include<cstdio>
double eps=1e-8;
using namespace std;
double a[101][101],ans[101];//Ç°Ò»¸ö´ú±íÐÐ
int n;
void Goh(){
for(int i=1;i<=n;i++){
int r=i;
for(int j=1;j<=n;j++){
if(abs(a[j][j])>eps && j<i) continue;
if(fabs(a[j][i])>fabs(a[r][i]))
r=j;
}
if(fabs(a[r][i])<eps){
continue;
}
if(r!=i) swap(a[i],a[r]);
double div=a[i][i];
for(int j=i;j<=n+1;j++) a[i][j]/=div;
for(int j=i+1;j<=n;j++){
div=a[j][i];
for(int k=i;k<=n+1;k++){
a[j][k]-=a[i][k]*div;
}
}
}
ans[n]=a[n][n+1];
for(int i=n-1;i>=1;i--){
ans[i]=a[i][n+1];
for(int j=n;j>i;j--) ans[i]-=ans[j]*a[i][j],a[i][n+1]-=ans[j]*a[i][j],a[i][j]=0;
}
int key=1;
for(int i=1;i<=n;i++){
if(fabs(a[i][i])<eps){
if(fabs(a[i][n+1])>eps) key=-1;
else if(key!=-1) key=0;
}
}
if(key!=1){
cout<<key;
exit(0);
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
cin>>a[i][j];
Goh();
for(int i=1;i<=n;i++){
if(fabs(ans[i])<eps) printf("x%d=0\n",i);
printf("x%d=%.2lf\n",i,ans[i]);
}
}
欧拉函数
#include<iostream>
#include<cmath>
using namespace std;
const int N=1e7+5;
int phi[N],prime[N];
bool not_prime[N];
int eular_phi(int n){
int m=(int)(sqrt(n));
int ans=n;
for(int i=2;i<=m;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
}
if(n>1) ans=ans/n*(n-1);
return ans;
}
void getEular(int n){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!not_prime[i]){
prime[++prime[0]]=i;
phi[i]=i-1;
}
for(int j=1;j<=prime[0];j++){
int k=i* prime[j];
if(k>n) break;
not_prime[k]=1;
if(i%prime[j]==0){
phi[k]=phi[i]*prime[j];
break;
}
else phi[k]=phi[i]*(prime[j]-1);
}
}
}
int main(){
cout<<"1Ϊ²éѯn¤ÎÅ·Àº¯ÊýÖµ,2Ϊ²éѯ1~n\nÇëÊäÈë:";
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int op;
cin>>op;
int n;
cin>>n;
if(op==1){
cout<<eular_phi(n);
}
else{
getEular(n);
for(int i=1;i<=n;i++){
cout<<phi[i]<<'\n';
}
}
}
扩欧
#include<iostream>
using namespace std;
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1;
y=0;
return a;
}
int res=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return res;
}
int main(){
int a,b,x=0,y=0;
cin>>a>>b;
exgcd(a,b,x,y);
cout<<x<<" "<<y;
// cout<<(x%b+b)%b;
}
数据结构
树状数组
单点修改,区间查询
#include<iostream>
#include<cstring>
using namespace std;
const int N=5*1e5+100;
int c[N],a[N],n;
int lower_bit(int x){
return x&(-x);
}
void AddPoint(int x,int w){
while(x<=n){
c[x]+=w;
x+=lower_bit(x);
}
}
int Sum(int l,int r){
int sum=0;
while(r>=l){
sum+=c[r];
r-=lower_bit(r);
}
return sum;
}
void SumPrint(int l,int r){
cout<<Sum(1,r)-Sum(1,l-1)<<endl;
}
int main(){
int m;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
AddPoint(i,a[i]);
}
cin>>m;
string x;
int y,z;
for(int i=1;i<=m;i++){
cin>>x>>y>>z;
if(x=="ADD") AddPoint(y,z);
else SumPrint(y,z);
}
}
区间修改,区间查询
#include<iostream>
#include<cstring>
using namespace std;
const int N=5*1e5+100;
int c[N],a[N],n,b[N];
int lower_bit(int x){
return x&(-x);
}
void AddPoint(int x,int w){
while(x<=n){
c[x]+=w;
x+=lower_bit(x);
}
}
void Add(int l,int r,int w){
AddPoint(l,w);
AddPoint(r+1,-w);
}
int Sum(int l,int r){
int sum=0;
while(r>=l){
sum+=c[r];
r-=lower_bit(r);
}
return sum;
}
void SumPrint(int l){
cout<<Sum(1,l)<<endl;
}
int main(){
int m;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i]-a[i-1];
AddPoint(i,b[i]);
}
string x;
int y,z,h;
cin>>m;
for(int i=1;i<=m;i++){
cin>>x;
if(x=="ADD"){
cin>>y>>z>>h;
Add(y,z,h);
}
else {
cin>>y;
SumPrint(y);
}
}
}
线段树
#include<iostream>
#include<cstring>
#define lid id<<1
#define rid id<<1|1
using namespace std;
int a[100001];
struct Node{
int l,r,sum,lazy;
}d[500001];
void PushDown(int id){
if(d[id].lazy){
d[lid].lazy+=d[id].lazy;
d[rid].lazy+=d[id].lazy;
d[lid].sum+=(d[lid].r-d[lid].l+1)*d[id].lazy;
d[rid].sum+=(d[rid].r-d[rid].l+1)*d[id].lazy;
d[id].lazy=0;
}
}
void Build(int id,int l,int r){
d[id].l=l;
d[id].r=r;
if(l==r){
d[id].sum=a[l];
return;
}
int mid=(l+r)>>2;
Build(lid,l,mid);
Build(rid,mid+1,r);
d[id].sum=d[lid].sum+d[rid].sum;
}
int Sum(int id,int l,int r){
if(l<=d[id].l && d[id].r<=r) return d[id].sum;
PushDown(id);
int sum=0;
if(l<=d[lid].r) sum+=Sum(lid,l,r);
if(r>d[lid].r) sum+=Sum(rid,l,r);
return sum;
}
void Update(int id,int l,int r,int w){
if(l<=d[id].l && d[id].r<=r){
d[id].sum+=(d[id].r-d[id].l+1)*w;
d[id].lazy+=w;
return;
}
PushDown(id);
if(l<=d[lid].r) Update(lid,l,r,w);
if(r>d[lid].r) Update(rid,l,r,w);
d[id].sum=d[lid].sum+d[rid].sum;
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,m,y,z,g;
string x;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
Build(1,1,n);
cin>>m;
for(int i=1;i<=m;i++){
cin>>x;
if(x=="ADD"){
cin>>y>>z>>g;
Update(1,y,z,g);
}
else{
cin>>y>>z;
cout<<Sum(1,y,z)<<endl;
}
}
}
单调队列
#include<cstdio>
int maxn[10000001],minl[10000001],x[10000001];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&x[i]);
int head=0,tail=0;
for(int i=1;i<m;i++){
while(head<=tail&&x[minl[tail]]>x[i]) tail--;
minl[++tail]=i;
}
for(int i=m;i<=n;i++){
while(head<=tail&&x[minl[tail]]>x[i]) tail--;
minl[++tail]=i;
while(minl[head]<=i-m) head++;
printf("%d ",x[minl[head]]);
}
printf("\n");
head=0,tail=0;
for(int i=1;i<m;i++){
while(head<=tail&&x[maxn[tail]]<x[i]) tail--;
maxn[++tail]=i;
}
for(int i=m;i<=n;i++){
while(head<=tail&&x[maxn[tail]]<x[i]) tail--;
maxn[++tail]=i;
while(maxn[head]<=i-m) head++;
printf("%d ",x[maxn[head]]);
}
}
单调栈
#include<cstdio>
#include<iostream>
#include<stack>
using namespace std;
int x[1000001],houseVal[1000001];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) cin>>x[i];
std::stack <int> ad;
for(int i=1;i<=n+1;i++){
while((!ad.empty())&&(x[ad.top()]>x[i])){
houseVal[ad.top()]=i-ad.top();
ad.pop();
}
ad.push(i);
}
for(int i=n;i>=0;i--){
while((!ad.empty())&&(x[ad.top()]>x[i])){
houseVal[ad.top()]+=ad.top()-i;
ad.pop();
}
ad.push(i);
}
int maxn=0;
for(int i=1;i<=n;i++){
maxn=max(maxn,x[i]*(houseVal[i]-1));
}
cout<<maxn;
}
ST表
#include<iostream>
#include<cmath>
using namespace std;
int dp[101][101];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>dp[i][0];
}
for(int j=1;j<=10;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
int x,y,k;
cin>>x>>y;
k=log2(y-x+1);
cout<<max(dp[x][k],dp[y-(1<<k)+1][k]);
}
分块
#include<iostream>
#include<cmath>
using namespace std;
#define int long long
int id[114514],n,a[114514];
struct kuai{
int sum,l,r,lazy;
}block[114514];
int Sum(int l,int r){
int ans=0,lid=id[l],rid=id[r],k=0;
if(lid==rid){
for(int i=l;i<=r;i++) ans+=(a[i]+block[lid].lazy);//暴力求和
}
else{
for(int i=l;i<=block[lid].r;i++) ans+=(a[i]+block[lid].lazy);//左散块
for(int i=lid+1;i<rid;i++) ans+=block[i].sum,k+=sqrt(n);//中间整块
for(int i=block[rid].l;i<=r;i++) ans+=(a[i]+block[rid].lazy);//右散块
}
return ans;
}
void Update(int l,int r,int w){//同上
int lid=id[l],rid=id[r];
if(lid==rid){
for(int i=l;i<=r;i++) a[i]+=w,block[lid].sum+=w;
}
else{
for(int i=l;i<=block[lid].r;i++) a[i]+=w,block[lid].sum+=w;
for(int i=lid+1;i<rid;i++) block[i].sum+=(block[i].r-block[i].l+1)*w,block[i].lazy+=w;
for(int i=block[rid].l;i<=r;i++) a[i]+=w,block[rid].sum+=w;
}
}
signed main(){
cin>>n;
int m;
cin>>m;
int sq=sqrt(n)+1;
for(int i=1;i<=n;i++){
cin>>a[i];
id[i]=(i-1)/sq+1;
block[id[i]].sum+=a[i];
}
for(int i=1;i<=n/sq;i++){
block[i].l=sq*(i-1)+1;
block[i].r=sq*i;
}
if(n%sq!=0){
block[n/sq+1].l=block[n/sq].r+1;
block[n/sq+1].r=n;
}
for(int i=1;i<=m;i++){
char op;
int x,y,z;
cin>>op>>x>>y;
if(op=='Q'){
cout<<Sum(x,y)<<"\n";
}
else{
cin>>z;
Update(x,y,z);
}
}
}
莫队
普通莫队
#include<iostream>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
int belong[1145140],cnt[1000001],aa[114514],now,ans[1145140];
struct Q{
int id,l,r;
}q[1145140];
int read(){//快读
char ch=getchar();int res=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) res=(res<<1)+(res<<3)+ch-48,ch=getchar();
return res;
}
void print(int x){
if(x/10) print(x/10);
putchar(x%10+'0');
}
bool cmp(Q a,Q b){//卡常
return (belong[a.l]^belong[b.l])?(belong[a.l]<belong[b.l]):((belong[a.l]&1)?a.r<b.r:a.r>b.r);
}
inline void del(int x){//卡常时不用它
if(cnt[aa[x]]==1) now--;
cnt[aa[x]]--;
}
inline void add(int x){
if(!cnt[aa[x]]) now++;
cnt[aa[x]]++;
}
signed main(){
int n,m;
cin>>n;
for(int i=1;i<=n;i++){
aa[i]=read();
}
cin>>m;
int sq=n/sqrt(m);
for(int i=1;i<=n;i++){
belong[i]=(i-1)/sq+1;
}
for(int i=1;i<=m;i++){
q[i].l=read(),q[i].r=read();
q[i].id=i;
}
sort(q+1,q+1+m,cmp);//莫队核心之一
int l=1,r=0;
for(int i=1;i<=m;i++){
int ql=q[i].l,qr=q[i].r;
while(l<ql) now-=!--cnt[aa[l++]];//卡常
while(l>ql) now+=!cnt[aa[--l]]++;
while(r<qr) now+=!cnt[aa[++r]]++;
while(r>qr) now-=!--cnt[aa[r--]];
ans[q[i].id]=now;
}
for(int i=1;i<=m;i++){
print(ans[i]);
putchar('\n');
}
}
带修莫队
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=143333;
int belong[N],a[N],cnt_q,cnt_ch,timer[1000010],now,ans[N];
struct Node{
int l,r,time,id;
}q[N],ch[N];
inline int read(){
char ch=getchar();
int res=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
return res;
}
void print(int x){
if(x/10) print(x/10);
putchar(x%10+'0');
}
bool cmp(Node a,Node b){
return (belong[a.l]^belong[b.l])?(belong[a.l]<belong[b.l]):((belong[a.r]^belong[b.r])?(belong[a.r]<belong[b.r]):(a.time<b.time));
}
int main(){
int n,m;
n=read(),m=read();
int sq=pow(n,0.66666);
for(int i=1;i<=n;i++){
a[i]=read();
belong[i]=(i-1)/sq+1;
}
for(int i=1;i<=m;i++){
int x,y;
char op;
cin>>op;
x=read(),y=read();
if(op=='Q') q[++cnt_q].l=x,q[cnt_q].r=y,q[cnt_q].id=cnt_q,q[cnt_q].time=cnt_ch;
else ch[++cnt_ch].l=x,ch[cnt_ch].id=cnt_ch,ch[cnt_ch].r=y;
}
sort(q+1,q+1+cnt_q,cmp);
int l=1,r=0,now_time=0;
for(int i=1;i<=cnt_q;i++){
int posl=q[i].l,posr=q[i].r,post=q[i].time;
while(l<posl) now-=!--timer[a[l++]];
while(l>posl) now+=!timer[a[--l]]++;
while(r<posr) now+=!timer[a[++r]]++;
while(r>posr) now-=!--timer[a[r--]];
while(now_time<post){
now_time++;
if(posl<=ch[now_time].l && ch[now_time].l<=posr) now+=(!timer[ch[now_time].r]++)-(!--timer[a[ch[now_time].l]]);
swap(a[ch[now_time].l],ch[now_time].r);
}
while(now_time>post){
if(posl<=ch[now_time].l && ch[now_time].l<=posr) now+=(!timer[ch[now_time].r]++)-(!--timer[a[ch[now_time].l]]);
swap(a[ch[now_time].l],ch[now_time].r);
now_time--;
}
ans[q[i].id]=now;
}
for(int i=1;i<=cnt_q;i++) print(ans[i]),putchar('\n');
}
回滚莫队
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N=1e5+100;
int T[N],en[N],cnt1[N],cnt2[N],a[N],ans[N],belong[N],aa[N],en2[N];
struct Node{
int l,r,id;
}q[N];
bool cmp(Node a,Node b){
return (belong[a.l]^belong[b.l])?(belong[a.l]<belong[b.l]):(a.r<b.r);
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,m;
cin>>n>>m;
int sq=ceil(n/sqrt(m));
for(int i=1;i<=n;i++){
cin>>a[i];
T[i]=a[i];
aa[i]=a[i];
belong[i]=(i-1)/sq+1;
en2[belong[i]]=i;
}
for(int i=1;i<=m;i++){
cin>>q[i].l>>q[i].r;
q[i].id=i;
}
sort(aa+1,aa+1+n);
int newn=unique(aa+1,aa+1+n)-(aa+1);
for(int i=1;i<=n;i++){
a[i]=lower_bound(aa+1,aa+1+newn,a[i])-aa;
}
sort(q+1,q+1+m,cmp);
int qwq=belong[n];
int l,r,now,tag,j=1;
for(int i=1;i<=qwq;i++){
l=en2[i]+1,r=en2[i];
memset(cnt1,0,sizeof(cnt1));
now=0,tag=0;
for(;belong[q[j].l]==i;j++){
int posl=q[j].l,posr=q[j].r;
// cerr<<q[j].id<<" "<<posl<<" "<<posr<<"\n";
tag=0;
if(belong[posl]==belong[posr]){
for(int k=posl;k<=posr;k++){
cnt2[a[k]]++;
tag=max(tag,cnt2[a[k]]*T[k]);
}
ans[q[j].id]=tag;
for(int k=posl;k<=posr;k++){
cnt2[a[k]]=0;
}
continue;
}
while(r<posr){
r++;
cnt1[a[r]]++;
now=max(now,cnt1[a[r]]*T[r]);
}
tag=now;
while(l>posl){
l--;
cnt1[a[l]]++;
now=max(now,cnt1[a[l]]*T[l]);
}
ans[q[j].id]=now;
now=tag;
while(l<en2[i]+1){
cnt1[a[l]]--;
// cerr<<T[l]<<" : "<<cnt1[a[l]]<<" ";
l++;
}
// cerr<<q[j].id<<" "<<posl<<" "<<posr<<"\n";
}
}
for(int i=1;i<=m;i++) cout<<ans[i]<<"\n";
}
KMP
#include<iostream>
using namespace std;
const int N_KMP=1e5+10;
int fail[N_KMP],len_s_K,len_t_K;
string s_Kmp,t_Kmp;
void Fail(){
for(int i=1;i<len_s_K;i++){//!下标从零开始
int j=fail[i];
while(j && (s_Kmp[i]!=s_Kmp[j])){
j=fail[j];//?跳fail指针,因为如果失配,则一定再前一个的bored的bored
}
if(s_Kmp[i]==s_Kmp[j]) j++;
fail[i+1]=j;//!如果使用0开始的下标,则集体-1,注意下标从1~len_s
}
}
int KMP_count(){//返回个数
int ans=0;
for(int i=0,j=0;i<len_t_K;i++){
while(j && (s_Kmp[j]!=t_Kmp[i])){
j=fail[j];//?跳fail指针
}
if(s_Kmp[j]==t_Kmp[i]) j++;
if(j==len_s_K){
ans++;
j=fail[j];
}
}
return ans;
}
int main(){
cin>>s_Kmp>>t_Kmp;
len_s_K=s_Kmp.size();
len_t_K=t_Kmp.size();
Fail();
cout<<KMP_count();
}
线段树合并
//单点修改,区间查询(线段树合并+动态开点 )
#include<iostream>
using namespace std;
#define lid d[id].ls
#define rid d[id].rs
int cnt;
struct Node{
int sum,ls,rs;
}d[4000001];
void Update(int &id,int x,int y,int w,int pos){//修改
if(!id) id=++cnt;
if(x==y){
d[id].sum+=w;
return;
}
int mid=(x+y)>>1;
if(pos<=mid) Update(lid,x,mid,w,pos);
else Update(rid,mid+1,y,w,pos);
d[id].sum=d[lid].sum+d[rid].sum;
}
int Quary(int id,int x,int y,int l,int r){//查询(单点),区间使用相同的方式(pushdown时无节点就新建一个awa)
if(!id) return 0;
if(l<=x && y<=r) return d[id].sum;
int mid=(x+y)>>1;
int sum=0;
if(l<=mid) sum=Quary(lid,x,mid,l,r);
if(r>mid) sum+=Quary(rid,mid+1,y,l,r);
return sum;
}
void merge(int &a,int b,int l,int r){
if(!a){
a=b;
return;
}
if(!b) return;
if(l==r){
//do something...
return;
}
int mid=(l+r)>>1;
merge(d[a].ls,d[b].ls,l,mid);
merge(d[a].rs,d[b].rs,mid+1,r);
//TODO pushup(a); // 进行pushup
}
int main(){
}
平衡树
有旋Treap
#include<iostream>
using namespace std;
#define lid d[id].l
#define rid d[id].r
int cnt_tree,ans;
struct Treap{
int l,r; //左孩子,右孩子
int siz; //大小
int cnt; //重复元素数量
int rank; //随机出来的优先度
int val; //值
}d[100005];
void Update_size(int id){//更新大小
d[id].siz=d[id].cnt+d[lid].siz+d[rid].siz;
}
void lrotate(int &id){
/* 左旋:也就是让右子节点变成根节点
* A C
* / \ / \
* B C ----> A E
* / \ / \
* D E B D
*/
int t=d[id].r; //记录右孩子
d[id].r=d[t].l; //A的右孩子改为C的左孩子
d[t].l=id; //C的左孩子改为A
d[t].siz=d[id].siz;//传递size
Update_size(id);//更新A的size
id=t;//换根
}
void rrotate(int &id){
/* 右旋:也就是让左子节点变成根节点
* A C
* / \ / \
* B C <---- A E
* / \ / \
* D E B D
*/
int t=d[id].l;//同上
d[id].l=d[t].r;
d[t].r=id;
d[t].siz=d[id].siz;
Update_size(id);
id=t;
}
void insert(int &id,int val){
if(!id){ //没有点新建点
id=++cnt_tree;
d[id].rank=rand();
d[id].siz=1;
d[id].cnt=1;
d[id].val=val;
return;
}
d[id].siz++; //大小++
if(val==d[id].val){
d[id].cnt++; //值相同,直接扔进去
}
else if(val<d[id].val){
insert(lid,val); //增加在左孩子里
if(d[lid].rank<d[id].rank){
rrotate(id); //为满足小根堆性质(上方优先度低于下方),需要右旋
}
}
else{
insert(rid,val); //同上
if(d[rid].rank<d[id].rank){
lrotate(id);
}
}
}
//用bool,0为未删点,1为删点
bool del(int &id,int val){
if(!val) return false; //如果没有点,不需要修改,所以return false
if(val==d[id].val){ //如果相等
if(d[id].cnt>1){ //有重复元素则直接删除
d[id].cnt--;
d[id].siz--;
return true;
}
if(lid==0 || rid==0){ //只有一个孩子,或没有孩子,不存在内讧,故直接赋值
id=lid+rid;
return true;
}
else if(d[lid].rank<d[rid].rank){ //删完还要满足小根堆,故右旋
rrotate(id);
return del(id,val); //删点
}
else{
lrotate(id);
return del(id,val);
}
}
else if(val<d[id].val){
bool dele=del(lid,val); //点在左孩子,记录是否成功删点
if(dele) d[id].siz--;
return dele;
}
else{
bool dele=del(rid,val);
if(dele) d[id].siz--;
return dele;
}
}
int Query_Rank(int id,int val){ //查询排名
if(!id) return 0; //若 定义排名为比当前数小的数的个数+1 则此处应该为return 1;
if(val==d[id].val) return d[lid].siz+1; //仅比所有左侧节点大
else if(val<d[id].val) return Query_Rank(lid,val); //点在左孩子
else return d[lid].siz+d[id].cnt+Query_Rank(rid,val); //1.比所有左节点大,2.比该节点的所有重复元素大,3.点在右孩子
}
int Query_Num(int id,int val){ //查询排名为val的节点值
if(!id) return 0;
if(val<=d[lid].siz) return Query_Num(lid,val); //节点在左孩子
else if(val>d[lid].siz+d[id].cnt) return Query_Num(rid,val-d[lid].siz-d[id].cnt); //!节点在右孩子,但排名在右孩子里应减小
else return d[id].val; //不在左,不在右,就只能在自己里了呗awa
}
void Query_Pre(int id,int val){ //查询前驱
if(!id) return; //类似二分查找
if(val>d[id].val){ //!别弄反了
ans=id;
Query_Pre(rid,val);
}
else{
Query_Pre(lid,val);
}
}
void Query_Sub(int id,int val){
if(!id) return;
if(val<d[id].val){ //!别弄反了
ans=id;
Query_Sub(lid,val);
}
else{
Query_Sub(rid,val);
}
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,root=0;
cin>>n;
for(int i=1;i<=n;i++){
int op,x;
cin>>op>>x;
if(op==1){
insert(root,x);
}
if(op==2){
del(root,x);
}
if(op==3){
cout<<Query_Rank(root,x)<<"\n";
}
if(op==4){
cout<<Query_Num(root,x)<<"\n";
}
if(op==5){
ans=0;
Query_Pre(root,x);
cout<<d[ans].val<<"\n";
}
if(op==6){
ans=0;
Query_Sub(root,x);
cout<<d[ans].val<<"\n";
}
}
}
无旋Treap(FHQ)
#include<iostream>
#include<cstdlib>
using namespace std;
#define lid d[id].l
#define rid d[id].r
int cnt_tree=0,root=0,x=0,y=0,z=0;
struct Node{
int l,r; //左右孩子
int rank; //优先度(Treap特色)
int val; //值
int siz; //大小
}d[500005];
void Update(int id){ //更新大小
d[id].siz=1+d[lid].siz+d[rid].siz;
}
int New_Node(int v){ //新建节点
d[++cnt_tree].val=v;
d[cnt_tree].rank=rand();
d[cnt_tree].siz=1;
return cnt_tree;
}
int merge(int a,int b){ //合并
if(!a || !b){ //类似于线段树合并,有没有的直接返回另一个
return a+b;
}
if(d[a].rank<d[b].rank){ //优先度上方的要小
d[a].r=merge(d[a].r,b); //满足中序遍历顺序不变
Update(a); //更新
return a;
}
else{
d[b].l=merge(a,d[b].l); //同上
Update(b);
return b;
}
}
void split(int id,int val,int &a,int &b){ //此处为按值分裂
if(!id) a=b=0; //如果没有节点,赋0
else{
if(d[id].val<=val){ //需要分裂左子树
a=id;
split(rid,val,rid,b);
}
else{ //需要分裂右子树
b=id;
split(lid,val,a,lid);
}
Update(id);
}
}
void insert(int val){ //添加节点
split(root,val,x,y); //分为val和val+1
root=merge(merge(x,New_Node(val)),y); //将val加入其中
}
void del(int val){ //删除
split(root,val,x,z); //将整棵树分为val和val+1
split(x,val-1,x,y); //将val部分继续分为val-1与val
y=merge(d[y].l,d[y].r); //将val节点单独剔除
root=merge(merge(x,y),z); //还原
}
int kth(int id,int k){
while(true){
if(k<=d[lid].siz) id=lid; //排名小于左子树大小,说明k在左子树
else if(k==d[lid].siz+1) return id; //太巧了,直接返回awa
else k-=d[lid].siz+1,id=rid; //在右子树的排名需要下降
}
}
void Query_Rank(int val){ //查询排名
split(root,val-1,x,y); //分裂为val-1与val
cout<<d[x].siz+1<<"\n"; //与定义相符
root=merge(x,y); //还原
}
void Query_Num(int val){ //查询排名为val的值
cout<<d[kth(root,val)].val<<"\n"; //直接查找即可
}
void Query_Pre(int val){ //查找前驱
split(root,val-1,x,y); //分裂为val-1与val
cout<<d[kth(x,d[x].siz)].val<<"\n"; //在val-1部分寻找最大的即可
root=merge(x,y); //还原
}
void Query_Sub(int val){ //后继
split(root,val,x,y); //分为val和val+1
cout<<d[kth(y,1)].val<<"\n"; //在val+1部分寻找最小即可
root=merge(x,y); //还原
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
srand(123);
int n;cin>>n;
for(int i=1;i<=n;i++){
int op,a;
cin>>op>>a;
if(op==1){
insert(a);
}
if(op==2){
del(a);
}
if(op==3){
Query_Rank(a);
}
if(op==4){
Query_Num(a);
}
if(op==5){
Query_Pre(a);
}
if(op==6){
Query_Sub(a);
}
}
}
Splay
#include<iostream>
using namespace std;
#define lid d[id].ch[0]
#define rid d[id].ch[1]
int root,tot;
struct Node{
int siz,ch[2],fa,cnt,val; //不在过多介绍
}d[1000001];
void maintain(int id){ //更新大小
d[id].siz=d[lid].siz+d[rid].siz+d[id].cnt;
}
bool get(int id){ //是否为右孩子
return id==d[d[id].fa].ch[1];
}
void clear(int id){ //删点
d[id].siz=lid=rid=d[id].fa=d[id].val=d[id].cnt=0;
}
void rotate(int id){ //旋转,将id转为跟,所以需要判断是否为右孩子
//接下来以左旋为例
int y=d[id].fa,z=d[y].fa,chk=get(id); //获取父亲和爷爷
d[y].ch[chk]=d[id].ch[chk^1]; //将父亲的右孩子指向id的左孩子
if(d[id].ch[chk^1]) d[d[id].ch[chk^1]].fa=y; //如果有右孩子,则设置他的父亲
d[id].ch[chk^1]=y; //左孩子改为父亲
d[y].fa=id; //更改父亲的父亲
d[id].fa=z; //更改id的父亲为之前的爷爷
if(z) d[z].ch[y==d[z].ch[1]]=id; //如果有爷爷,则通过y==d[z].ch[1]来判断应该放于左孩子还是右孩子中(直接替换)
maintain(y); //更新
maintain(id); //更新
//爷爷不用更新,因为下方不会消失
}
void splay(int id){ //核心---splay
for(int f=d[id].fa;f=d[id].fa,f;rotate(id)){ //对应6种splay的情况处理,总之,最后结果是id变为root,保持了中序遍历不变,并保持了后续log的优秀复杂度(平衡)
if(d[f].fa) rotate(get(id)==get(f)?f:id);
}
root=id; //更新root
}
void insert(int val){ //插入
if(!root){ //没有根,新建一个
d[++tot].val=val;
d[tot].cnt++;
root=tot;
maintain(root);
return;
}
int id=root,f=0;
while(1){
if(val==d[id].val){ //如果有相同的,则cnt++即可
d[id].cnt++;
maintain(id);
maintain(f);
splay(id); //维持新进的点永远是root
return;
}
f=id;
id=d[id].ch[d[id].val<val]; //搜索树的性质
if(!id){ //如果没有,则新建
d[++tot].val=val;
d[tot].cnt++;
d[tot].fa=f;
d[f].ch[d[f].val<val]=tot;
maintain(tot);
maintain(f);
splay(tot); //维持新进的点永远是root
return;
}
}
}
int Query_Rank(int val){ //查询排名
int res=0,id=root;
while(1){
if(val<d[id].val){ //在左子树中
id=lid;
}
else{
res+=d[lid].siz; //先加上左子树大小
if(!id) return res+1; //没有了,直接return
if(val==d[id].val){ //太巧了,直接返回即可
splay(id); //维护root,为后续del做准备
return res+1;
}
res+=d[id].cnt;
id=rid; //在右子树中
}
}
}
int kth(int val){ //查询排名为val的值
int id=root;
while(1){
if(lid && val<=d[lid].siz){ //在左子树
id=lid;
}
else{ //在右子树
val-=d[id].cnt+d[lid].siz;
if(val<=0){ //如果减为非正数,证明就是id了
splay(id); //维护splay性质
return d[id].val; //返回值
}
id=rid; //否则继续在右子树中寻找
}
}
}
int Query_Pre(){ //因为insert了,所以root已经是val了
int id=d[root].ch[0]; //正常的搜索树的查找方式
if(!id) return id;
while(rid) id=rid;
splay(id);
return id;
}
int Query_Sub(){ //同上
int id=d[root].ch[1];
if(!id) return id;
while(lid) id=lid;
splay(id);
return id;
}
void del(int val){ //删除
Query_Rank(val); //先查询,使得val为root
if(d[root].cnt>1){ //太巧了,直接--;
d[root].cnt--;
maintain(root);
return;
}
if(!d[root].ch[0] && !d[root].ch[1]){ //孤立无援,真是令人惋惜
clear(root);
root=0;
return;
}
if(!d[root].ch[0]){ //直接使右孩子代替root
int id=root;
root=d[root].ch[1];
d[root].fa=0;
clear(id);
return;
}
if(!d[root].ch[1]){ //直接使左孩子代替root
int id=root;
root=d[root].ch[0];
d[root].fa=0;
clear(id);
return;
}
int id=root,x=Query_Pre(); //找到比他小的最大数
d[rid].fa=x; //将跟的右孩子直接接在前驱上
d[x].ch[1]=rid;
clear(id);
maintain(root);
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++){
int op,x;
cin>>op>>x;
if(op==1){
insert(x);
}
if(op==2){
del(x);
}
if(op==3){
cout<<Query_Rank(x)<<"\n";
}
if(op==4){
cout<<kth(x)<<"\n";
}
if(op==5){
insert(x);
cout<<d[Query_Pre()].val<<"\n";
del(x);
}
if(op==6){
insert(x);
cout<<d[Query_Sub()].val<<"\n";
del(x);
}
}
}
杂项(不知道算什么的东西)
矩阵快速幂
#include<iostream>
#include<cstring>
using namespace std;
long long mod=1;
struct Mat{
long long m,n;
long long a[11][11];
void resize(long long x,long long y){
n=x;
m=y;
}
Mat operator * (const Mat & A) const{
Mat res;
res.resize(n,A.m);
memset(res.a,0,sizeof(res.a));
for(int i=1;i<=n;i++){
for(int j=1;j<=A.m;j++){
for(int k=1;k<=m;k++){
res.a[i][j]=(a[i][k]*A.a[k][j]+res.a[i][j])%mod;
}
}
}
return res;
}
};
Mat qpow(Mat A,long long b){
Mat res;
res.resize(2,2);
res.a[1][1]=res.a[1][2]=res.a[2][1] =res.a[2][2]=1;
while(b){
if(b&1) res=res*A;
A=A*A;
b>>=1;
}
return res;
}
int main(){
long long n;
cin>>n>>mod;
Mat b;
b.resize(2,2);
b.a[1][1]=b.a[1][2]=b.a[2][1]=1;
b.a[2][2]=0;
Mat re=qpow(b,n-3);
printf("%lld",(re.a[1][1]+re.a[1][2])%mod);
}
动态规划DP
背包DP
01背包
#include<iostream>
#include<cmath>
using namespace std;
int n[1001],v[1001],f[1001];//使用j空间能出现的最大价值
int main(){
int N,V;
cin>>N>>V;
for(int i=1;i<=N;i++){
cin>>v[i]>>n[i];
}
for(int i=1;i<=N;i++){
for(int j=V;j>=v[i];j--){
f[j]=max(f[j],f[j-v[i]]+n[i]);
}
}
int l=0;
for(int i=1;i<=V;i++){
l=max(l,f[i]);
}
cout<<l;
}
多重背包
#include<iostream>
#include<cmath>
using namespace std;
int n[1001],v[1001],f[1001],c[1001];//使用j空间能出现的最大价值
int main(){
int N,V;
cin>>N>>V;
for(int i=1;i<=N;i++){
cin>>v[i]>>n[i]>>c[i];
}
for(int i=1;i<=N;i++){
for(int k=1;k<=min(V/v[i],c[i]);k++)
for(int j=V;j>=v[i]*k;j--){
f[j]=max(f[j],f[j-k*v[i]]+k*n[i]);
}
}
int l=0;
for(int i=1;i<=V;i++){
l=max(l,f[i]);
}
cout<<l;
}
完全背包
#include<iostream>
#include<cmath>
using namespace std;
int n[1001],v[1001],f[1001];
int main(){
int N,V;
cin>>V>>N;
for(int i=1;i<=N;i++){
cin>>v[i]>>n[i];
}
for(int i=1;i<=N;i++){
for(int k=1;k<=V/v[i];k++)
for(int j=V;j>=v[i]*k;j--){
f[j]=max(f[j],f[j-k*v[i]]+k*n[i]);
}
}
int l=0;
for(int i=1;i<=V;i++){
l=max(l,f[i]);
}
cout<<"max="<<l;
}
二进制分组背包(放到混合背包里了)
#include<iostream>
#include<cmath>
using namespace std;
int n[1001],v[1001],f[1001];
int main(){
int N,V;
cin>>V>>N;
for(int i=1;i<=N;i++){
cin>>v[i]>>n[i];
}
for(int i=1;i<=N;i++){
for(int k=1;k<=V/v[i];k++)
for(int j=V;j>=v[i]*k;j--){
f[j]=max(f[j],f[j-k*v[i]]+k*n[i]);
}
}
int l=0;
for(int i=1;i<=V;i++){
l=max(l,f[i]);
}
cout<<"max="<<l;
}
线性DP
LIS
#include<iostream>
#include<algorithm>
using namespace std;
int n,t[1000001],c[1000001];
inline int lowbit(int x){
return x&(-x);
}
void Update(int x,int w){
while(x<=n){c[x]=max(c[x],w),x+=lowbit(x);}
}
int Sum(int x){
int ans=0;
while(x){
ans=max(ans,c[x]);
x-=lowbit(x);
}
return ans;
}
struct Node{
int id,val;
}a[1000001];
bool cmp(Node a,Node b){
return a.val<b.val;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].val;
a[i].id=i;
}
sort(a+1,a+1+n,cmp);
int ans=0;
for(int i=1;i<=n;i++){
t[i]=Sum(a[i].id)+1;
Update(a[i].id,t[i]);
ans=max(ans,t[i]);
}
cout<<ans;
}
最长公共子序列
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int dp[1001][1001];
char a[1001],b[1001];
int main(){
scanf("%s%s",a+1,b+1);
int maxn=0;
for(int i=1;b[i];i++){
for(int j=1;a[j];j++){
if(b[i]==a[j]) dp[i][j]=dp[i-1][j-1]+1;
if(maxn<dp[i][j]) maxn=dp[i][j];
}
}
cout<<maxn;
}