No_wonderの模板们
更多模板
蒟蒻就学了一点点东西,距离建立一个成熟的模板库还是很远na,加油!!!
其他类
模拟退火
真正的人品无惧于参数的调控。
int SA()//模拟退火
{
double t=10000,now=ans,xz=0.97;
while(t>0.0001)
{
int x=rand()%n+1,y=rand()%n+1;//随机匹配
swap(A[x],A[y]); //随机到另一个状态
double res=calc(); //算出此时的解
if(res<now ||exp(-ch)/t>(double)(rand()%100/100.00))
now=res; //更改最优解
else
swap(A[x],A[y]); //不转移解的话就把状态换回来
t*=xs;
}
}
归并排序
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=1e5+5; //100005
int a[MAXN], temp[MAXN], n;
void MergeSort(int l, int r) //再次提醒函数慎用inline,不清楚能不能用就不要用
{
int mid=(l+r)>>1;
if(l==r) return;
MergeSort(l, mid);
MergeSort(mid+1, r);
int i=l, j=mid+1, k=l; //开始2路归并
while(i<=mid && j<=r)
{
if(a[i]<=a[j]) temp[k++]=a[i++];
else temp[k++]=a[j++];
}
while(i<=mid) temp[k++]=a[i++];
while(j<=r) temp[k++]=a[j++];
for(int i=l; i<=r; i++) a[i]=temp[i];
return;
}
int main(void)
{
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
MergeSort(1, n);
for(int i=1; i<=n; i++) printf("%d ", a[i]);
return 0;
}
高精度加减乘
#include<bits/stdc++.h>
using namespace std;
void init(int *a,int n)
{
for(int i=0;i<n;i++)
a[i]=0;
char s[200];
scanf("%s",s);
a[0]=strlen(s);
for(int i=1;i<=a[0];i++)
a[i]=s[a[0]-i]-'0';
return ;
}
void print(int *a)
{
for(int i=a[0];i>=1;i--)
printf("%d",a[i]);
printf("\n");
return ;
}
void sum(int *a,int *b,int *c,int n)
{
for(int i=0;i<n;i++)
c[i]=0;
int i=1;
int jw=0;
while(i<=a[0]||i<=b[0])
{
c[i]=a[i]+b[i]+jw;
jw=c[i]/10;
c[i]=c[i]%10;
i++;
}
c[i]=jw;
if(c[i])c[0]=i;
else c[0]=i-1;
}
int cmp(int *a,int *b)
{
if(a[0]>b[0])return 1;
else if(a[0]<b[0])return 0;
else
{
for(int i=a[0];i>=1;i--)
{
if(a[i]<b[i])return 0;
if(a[i]>b[i])return 1;
}
}
return 1;
}
void sub(int *a,int *b,int *c,int n)
{
for(int i=0;i<n;i++)
c[i]=0;
int i=1;
if(cmp(a,b))
{
while(i<=a[0]||i<=b[0])
{
c[i]=a[i]-b[i];
if(c[i]<0)
{
a[i+1]--;
c[i]+=10;
}
i++;
}
while(c[i]==0&&i>1)i--;
c[0]=i;
}
else
{
printf("-");
while(i<=a[0]||i<=b[0])
{
c[i]=b[i]-a[i];
if(c[i]<0)
{
b[i+1]--;
c[i]+=10;
}
i++;
}
while(c[i]==0&&i>1)i--;
c[0]=i;
return ;
}
}
void jh(int *a,int *b)
{
for(int i=0;i<200;i++)
a[i]=0;
for(int i=b[0];i>=0;i--)
a[i]=b[i];
}
void mul(int *a,int *b,int *c,int n)
{
for(int i=0;i<200;i++)
c[i]=0;
for(int i=1;i<=a[0];i++)
{
int jw=0;
for(int j=1;j<=b[0];j++)
{
c[i+j-1]+=a[i]*b[i]+jw;
jw=c[i+j-1]/10;
c[i+j-1]%=10;
}
c[i+b[0]]=jw;
i++;
}
c[0]=a[0]+b[0];
while(!c[c[0]]&&c[0]>1)c[0]--;
return ;
}
int main()
{
int a[2000],b[2000],c[2000];
init(a,2000);
init(b,2000);
//print(a);
//print(b);
//sum(a,b,c,2000);
//print(c);
sub(a,b,c,2000);
print(c);
//mul(a,b,c,2000);
//print(c);
//mulx(a,3);
///print(a);
return 0;
}
不怕死就用的八聚氧
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(3,"Ofast","inline")
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
%:pragma GCC optimize("-fgcse")
%:pragma GCC optimize("-fgcse-lm")
%:pragma GCC optimize("-fipa-sra")
%:pragma GCC optimize("-ftree-pre")
%:pragma GCC optimize("-ftree-vrp")
%:pragma GCC optimize("-fpeephole2")
%:pragma GCC optimize("-ffast-math")
%:pragma GCC optimize("-fsched-spec")
%:pragma GCC optimize("unroll-loops")
%:pragma GCC optimize("-falign-jumps")
%:pragma GCC optimize("-falign-loops")
%:pragma GCC optimize("-falign-labels")
%:pragma GCC optimize("-fdevirtualize")
%:pragma GCC optimize("-fcaller-saves")
%:pragma GCC optimize("-fcrossjumping")
%:pragma GCC optimize("-fthread-jumps")
%:pragma GCC optimize("-funroll-loops")
%:pragma GCC optimize("-fwhole-program")
%:pragma GCC optimize("-freorder-blocks")
%:pragma GCC optimize("-fschedule-insns")
%:pragma GCC optimize("inline-functions")
%:pragma GCC optimize("-ftree-tail-merge")
%:pragma GCC optimize("-fschedule-insns2")
%:pragma GCC optimize("-fstrict-aliasing")
%:pragma GCC optimize("-fstrict-overflow")
%:pragma GCC optimize("-falign-functions")
%:pragma GCC optimize("-fcse-skip-blocks")
%:pragma GCC optimize("-fcse-follow-jumps")
%:pragma GCC optimize("-fsched-interblock")
%:pragma GCC optimize("-fpartial-inlining")
%:pragma GCC optimize("no-stack-protector")
%:pragma GCC optimize("-freorder-functions")
%:pragma GCC optimize("-findirect-inlining")
%:pragma GCC optimize("-fhoist-adjacent-loads")
%:pragma GCC optimize("-frerun-cse-after-loop")
%:pragma GCC optimize("inline-small-functions")
%:pragma GCC optimize("-finline-small-functions")
%:pragma GCC optimize("-ftree-switch-conversion")
%:pragma GCC optimize("-foptimize-sibling-calls")
%:pragma GCC optimize("-fexpensive-optimizations")
%:pragma GCC optimize("-funsafe-loop-optimizations")
%:pragma GCC optimize("inline-functions-called-once")
%:pragma GCC optimize("-fdelete-null-pointer-checks")
图论
最短路
dijkstra堆优化
洛谷P1339
我会线段树!我会斐波那契堆!!!
我会堆
#include<bits/stdc++.h>
#include<queue>
#define inf INT_MAX/2-1
using namespace std;
struct Edge{
int to,next,dis;
}e[100000];
struct dist{
int num,dis;
dist(int n,int d)
{
num=n;
dis=d;
}
bool operator < (const dist r)const
{
return dis>r.dis;
}
};
int n,m,c1,c2,num;
int head[100010],dis[100010],vis[100010];
void add(int from,int to,int dis)
{
e[++num].to=to;
e[num].next=head[from];
e[num].dis=dis;
head[from]=num;
}
void dijkstra(int now)
{
dis[now]=0;
priority_queue <dist> q;
q.push(dist(now,dis[now]));
while(!q.empty())
{
int u=q.top().num;
int v=q.top().dis;
q.pop();
if(vis[u])continue;
else
{
vis[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int to=e[i].to;
if(v+e[i].dis<dis[to])
{
dis[to]=v+e[i].dis;
q.push(dist(to,dis[to]));
}
}
}
}
}
int main()
{
cin>>n>>m>>c1>>c2;
for(int i=1;i<=m;i++)
{
int x,y,dis;
cin>>x>>y>>dis;
add(x,y,dis);
add(y,x,dis);
}
for(int i=0;i<=n;i++)
dis[i]=inf;
dijkstra(c1);
cout<<dis[c2];
}
SPFA
洛谷P1339
未优化,谁用谁知道
#include<bits/stdc++.h>
#include<queue>
#define inf 1000000
using namespace std;
int n,m,head[100010],cnt,c1,c2,dis[100010],vis[100010];
queue<int> q;
struct Edge{
int to;
int next;
int dist;
}e[100010];
void add(int from,int to,int dist)
{
e[++cnt].next=head[from];
e[cnt].to=to;
e[cnt].dist=dist;
head[from]=cnt;
}
void spfa(int now)
{
dis[now]=0;
vis[now]=1;
q.push(now);
while(!q.empty())
{
int t=q.front();
q.pop();
vis[t]=0;
for(int i=head[t];i;i=e[i].next)
{
if(dis[e[i].to]>dis[t]+e[i].dist)
{
dis[e[i].to]=dis[t]+e[i].dist;
if(!vis[e[i].to])
{
vis[e[i].to]=1;
q.push(e[i].to);
}
}
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&c1,&c2);
for(int i=1;i<=m;i++)
{
int x,y,dist;
scanf("%d%d%d",&x,&y,&dist);
add(x,y,dist);
add(y,x,dist);
}
memset(dis,inf,sizeof(dis));
spfa(c1);
printf("%d",dis[c2]);
return 0;
}
SPFA SLF+LLL
SPFA优化后的船新版本,老韩再也不怕我被卡7个点了!
//SPFA+SLF+LLL
#include<iostream>
#include<cstdio>
#include<cstring>
#include<deque>
using namespace std;
const int maxn=1e4+5, maxm=5e5+5, INF=2147483647;
int dis[maxn], v[maxn], n, m, s;
struct edge{
int t, w; edge *nxt;
edge(int to, int len, edge *next){ t=to, w=len, nxt=next; }
};
edge *h[maxn];
void add(int x, int y, int z){ h[x]=new edge(y, z, h[x]); }
void SPFA(int s)
{
int cnt=0, sum=0; //cnt为队列中元素个数,sum为队列中dis值总和
for(int i=1; i<=n; i++) dis[i]=(i==s) ? 0 : INF;
deque<int> Q; //Q为双端队列
Q.push_back(s), v[s]=1, cnt=1;
while(!Q.empty())
{
int x=Q.front();
while(cnt*dis[x]>sum) //取出来,放后去,直到找到一个比平均值小的点
{
Q.pop_front();
Q.push_back(x);
x=Q.front();
}
Q.pop_front();
cnt--, sum-=dis[x], v[x]=false; //出队后,更新队列大小及队列dis值之和
for(edge *p=h[x]; p; p=p->nxt)
if(dis[p->t]>dis[x]+p->w)
{
dis[p->t]=dis[x]+p->w;
if(!v[p->t])
{
v[p->t]=1;
if(Q.empty() || dis[p->t]>dis[Q.front()]) Q.push_back(p->t);
else Q.push_front(p->t);
cnt++, sum+=dis[p->t]; //入队后,更新队列大小及队列dis值之和
}
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &s);
for(int i=1, x, y, z; i<=m; i++) scanf("%d%d%d", &x, &y, &z), add(x,y,z);
SPFA(s);
for(int i=1; i<=n; i++) printf("%d ",dis[i]);
return 0;
}
01最短路
具体实现是用双端队列,0排在队头,1排在队尾,这样搜索的时候就会优先走0路
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<queue>
using namespace std;
int n,p,k,maxn;
int head[10010],cnt;
int d[10010],vis[10010];
struct Edge{
int to;
int next;
int dis;
}e[20020];
void add_edge(int from,int to,int dis)
{
e[++cnt].to=to;
e[cnt].next=head[from];
e[cnt].dis=dis;
head[from]=cnt;
}
bool check(int x)
{
memset(d,0,sizeof d);
memset(vis,0,sizeof vis);
deque <int> q;
q.push_back(1);
d[1]=0;
vis[1]=1;
while(!q.empty())
{
int a=q.front();
q.pop_front();
for(register int i=head[a];i;i=e[i].next)
{
int y=e[i].to;
if(!vis[y] || d[y]>=d[a]+1)
if(e[i].dis<=x)
{
vis[y]=1;
q.push_front(y);
d[y]=d[a];
}
else
{
vis[y]=1;
q.push_back(y);
d[y]=d[a]+1;
}
}
}
if(d[n]>k)
return 0;
return 1;
}
int main()
{
scanf("%d%d%d",&n,&p,&k);
for(register int i=1;i<=p;i++)
{
int ai,bi,li;
scanf("%d%d%d",&ai,&bi,&li);
add_edge(ai,bi,li);
add_edge(bi,ai,li);
maxn=max(maxn,li);
}
int l=1,r=maxn;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))
r=mid;
else
l=mid+1;
}
if(l!=1)
printf("%d",l);
else
printf("-1");
}
最小生成树
Pirm
#include<bits/stdc++.h>
#include<queue>
#define inf INT_MAX/4
using namespace std;
int n,m,cnt,ans,sum,now,dis[1000010],head[1000010],vis[1000010];
struct Edge{
int next;
int to;
int dist;
}e[1000010];
struct dist;
struct dist{
int num;
int dis;
dist(int pn,int pw)
{
num=pn;
dis=pw;
}
bool operator <(const dist &r)const
{
return dis>r.dis;
}
};
void add(int from,int to,int dist)
{
e[++cnt].next=head[from];
e[cnt].to=to;
e[cnt].dist=dist;
head[from]=cnt;
}
void Pirm()
{
for(int i=2;i<=n;i++)
dis[i]=inf;
priority_queue <dist> q;
q.push(dist(1,dis[1]));
while(!q.empty()&&sum<n)
{
int f1=q.top().dis,f2=q.top().num;
q.pop();
if(vis[f2])continue;
sum++;
ans+=f1;
vis[f2]=1;
for(int i=head[f2];i;i=e[i].next)
if(e[i].dist<dis[e[i].to])
{
dis[e[i].to]=e[i].dist;
q.push(dist(e[i].to,dis[e[i].to]));
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=2;i<=n;i++)
dis[i]=inf;
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
Pirm();
printf("%d",ans);
}
Kruskal
#include<bits/stdc++.h>
using namespace std;
int n,m,fa[100010],cnt,sum,ans;
struct Edge
{
int from;
int to;
int dist;
bool operator < (const Edge r)const
{
return dist<r.dist;
//如果要求最大生成树把这里的'<'改成'>'就可以了!
}
}a[1000010];
int find(int x)
{
if(x==fa[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++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
a[++cnt]=(Edge){u,v,w};
}
sort(a+1,a+cnt+1);
for(int i=1;i<=cnt;i++)
{
if(find(a[i].from)!=find(a[i].to))
{
sum++;
int f1=find(a[i].from),f2=find(a[i].to);
fa[f2]=f1;
ans+=a[i].dist;
if(sum==n-1)
{
printf("%d",ans);
return 0;
}
}
}
printf("orz");
}
拓扑排序
#include<bits/stdc++.h>
#include<queue>
using namespace std;
int n,m,cnt,ans,head[1000010],rd[1000010],flag,money[1000010];
struct Edge{
int to;
int next;
}e[1000010];
queue <int> q;
void add(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
money[i]=100;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(v,u);
rd[u]++;
}
for(int i=1;i<=n;i++)
if(!rd[i])
q.push(i);
int num=0;
while(!q.empty())
{
num++;
int now=q.front();
q.pop();
for(int i=head[now];i;i=e[i].next)
{
rd[e[i].to]--;
if(!rd[e[i].to])
q.push(e[i].to);
money[e[i].to]=max(money[now]+1,money[e[i].to]);
}
}
if(num==n)
flag=1;
if(!flag)
printf("Poor Xed");
else
{
for(int i=1;i<=n;i++)
ans+=money[i];
printf("%d",ans);
}
}
Tarjan之SCC+缩点
#include<bits/stdc++.h>
#include<stack>
using namespace std;
int num,head[100010],dfn[100010],low[100010],cnt,vis[100010];
int sum[100010],bj[100010],tot,qwq[100010];
struct Edge{
int to,next;
}edge[500010];
inline void add(int from,int to){
num++;
edge[num].to=to;
edge[num].next=head[from];
head[from]=num;
}
stack<int>s;
inline void tarjan(int x){
cnt++;
dfn[x]=low[x]=cnt;
s.push(x);
vis[x]=1;
for(register int i=head[x];i;i=edge[i].next){
int y=edge[i].to;
if(dfn[y]==0){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(vis[y]==1){
low[x]=min(low[x],dfn[y]);
}
}
if(low[x]==dfn[x]){
int z;
tot++;
while(s.top()!=x){
sum[tot]++;
z=s.top();
vis[z]=0;
bj[z]=tot;
s.pop();
}
sum[tot]++;
z=s.top();
vis[z]=0;
bj[z]=tot;
s.pop();
}
return;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
int x,y;
for(register int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(x,y);
}
for(register int i=1;i<=n;i++){
if(dfn[i]==0)
tarjan(i);
}
for(register int i=1;i<=n;i++){
for(register int j=head[i];j;j=edge[j].next){
int y=edge[j].to;
if(bj[i]!=bj[y]){
qwq[bj[y]]=1;
}
}
}
int ans=0;
for(register int i=1;i<=tot;i++){
if(qwq[i]==0){
ans++;
}
}
printf("%d",ans);
return 0;
}
LCA
倍增法
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
const int N=6e5;
int n,m,s,t,tot=0,f[N][20],d[N],ver[2*N],Next[2*N],head[N];
queue<int> q;
void add(int x,int y)
{
ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
}//邻接表存边操作。由于只求LCA时不关心边权,因此可以不存边权
void bfs()
{
q.push(s);
d[s]=1;//将根节点入队并标记
while(q.size())
{
int x=q.front();q.pop();//取出队头
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(d[y])
continue;
d[y]=d[x]+1;
f[y][0]=x;//初始化,因为y的父亲节点就是x
for(int j=1;j<=t;j++)
f[y][j]=f[f[y][j-1]][j-1];//递推f数组
q.push(y);
}
}
}
int lca(int x,int y)
{
if(d[x]>d[y])
swap(x,y);
for(int i=t;i>=0;i--)
if(d[f[y][i]]>=d[x])
y=f[y][i];//尝试上移y
if(x==y)
return x;//若相同说明找到了LCA
for(int i=t;i>=0;i--)
if(f[x][i]!=f[y][i])
{
x=f[x][i],y=f[y][i];
}//尝试上移x、y并保持它们不相遇
return f[x][0];//当前节点的父节点即为LCA
}
int main()
{
cin>>n>>m>>s;
t=log2(n)+1;
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
bfs();
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",lca(a,b));
}
return 0;
}
Tarjan(离线算法)
#include<bits/stdc++.h>
using namespace std;
int n,k,q,v[100000];
map<pair<int,int>,int> ans;//存答案
int t[100000][10],top[100000];//存储查询关系
struct node{
int l,r;
};
node s[100000];
/*并查集*/
int fa[100000];
void reset(){
for (int i=1;i<=n;i++){
fa[i]=i;
}
}
int getfa(int x){
return fa[x]==x?x:getfa(fa[x]);
}
void marge(int x,int y){
fa[getfa(y)]=getfa(x);
}
/*------*/
void tarjan(int x){
v[x]=1;//标记已访问
node p=s[x];//获取当前结点结构体
if (p.l!=-1){
tarjan(p.l);
marge(x,p.l);
}
if (p.r!=-1){
tarjan(p.r);
marge(x,p.r);
}//分别对l和r结点进行操作
for (int i=1;i<=top[x];i++){
if (v[t[x][i]]){
cout<<getfa(t[x][i])<<endl;
}//输出
}
}
int main(){
cin>>n>>q;
for (int i=1;i<=n;i++){
cin>>s[i].l>>s[i].r;
}
for (int i=1;i<=q;i++){
int a,b;
cin>>a>>b;
t[a][++top[a]]=b;//存储查询关系
t[b][++top[b]]=a;
}
reset();//初始化并查集
tarjan(1);//tarjan 求 LCA
}
树链剖分
#include <cstdio>
#include <cstdlib>
#define maxm 200010
struct edge{int to,len,next;}E[maxm];
int cnt,last[maxm],fa[maxm],top[maxm],deep[maxm],siz[maxm],son[maxm],val[maxm];
void addedge(int a,int b,int len=0)
{
E[++cnt]=(edge){b,len,last[a]},last[a]=cnt;
}
void dfs1(int x)
{
deep[x]=deep[fa[x]]+1;siz[x]=1;
for(int i=last[x];i;i=E[i].next)
{
int to=E[i].to;
if(fa[x]!=to&&!fa[to]){
val[to]=E[i].len;
fa[to]=x;
dfs1(to);
siz[x]+=siz[to];
if(siz[son[x]]<siz[to])son[x]=to;
}
}
}
void dfs2(int x)
{
if(x==son[fa[x]])top[x]=top[fa[x]];
else top[x]=x;
for(int i=last[x];i;i=E[i].next)if(fa[E[i].to]==x)dfs2(E[i].to);
}
void init(int root){dfs1(root),dfs2(root);}
int query(int x,int y)
{
for(;top[x]!=top[y];deep[top[x]]>deep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
return deep[x]<deep[y]?x:y;
}
int n,m,x,y,v;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);addedge(x,y,v);addedge(y,x,v);
}
init(1);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y));
}
return 0 ;
}
数据结构
线段树
区间加减带区间和
代码五分钟,bug两小时
洛谷P3372
#include<bits/stdc++.h>
#define ri register int
#define ls(k) (k)<<1
#define rs(k) (k)<<1|1
using namespace std;
int n,m,a[100010];
struct llk{
long long l,r,lazy,sum;
}tree[500010];
int read()
{
int w=1,s=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
void build(int i,int l,int r)
{
tree[i].l=l;
tree[i].r=r;
if(l==r)
{
tree[i].sum=a[l];
return ;
}
int mid=(l+r)>>1;
build(ls(i),l,mid);
build(rs(i),mid+1,r);
tree[i].sum=tree[ls(i)].sum+tree[rs(i)].sum;
}
void down(int i)
{
tree[ls(i)].lazy+=tree[i].lazy;
tree[ls(i)].sum+=(tree[ls(i)].r-tree[ls(i)].l+1)*tree[i].lazy;
tree[rs(i)].lazy+=tree[i].lazy;
tree[rs(i)].sum+=(tree[rs(i)].r-tree[rs(i)].l+1)*tree[i].lazy;
tree[i].lazy=0;
}
void update(int i,int l,int r,int k)
{
if(tree[i].l>r || tree[i].r<l)return ;
if(tree[i].l>=l && tree[i].r<=r)
{
tree[i].lazy+=k;
tree[i].sum+=(tree[i].r-tree[i].l+1)*k;
return ;
}
if(tree[i].lazy>0)down(i);
update(ls(i),l,r,k);
update(rs(i),l,r,k);
tree[i].sum=tree[ls(i)].sum+tree[rs(i)].sum;
}
long long query(int i,int l,int r)
{
if(tree[i].l>r || tree[i].r<l)return 0;
if(tree[i].l>=l&&tree[i].r<=r)return tree[i].sum;
if(tree[i].lazy>0)down(i);
return query(ls(i),l,r)+query(rs(i),l,r);
}
int main()
{
n=read();
m=read();
for(ri i=1;i<=n;i++)
a[i]=read();
build(1,1,n);
for(ri i=1;i<=m;i++)
{
int t,x,y;
t=read();
if(t==1)
{
int k;
x=read();
y=read();
k=read();
update(1,x,y,k);
}
else
{
x=read();
y=read();
printf("%lld\n",query(1,x,y));
}
}
}
乘+加
洛谷P3373
代码五十分钟,bug二十小时
#include<bits/stdc++.h>
#define ri register int
#define ls(k) (k)<<1//宏定义最外头要打上括号,这是良好的编程习惯 ((k)<<1)
#define rs(k) (k)<<1|1
using namespace std;
int n,m,p;
long long a[500050];
struct node{
long long sum,mul,add;
}tree[500050];
int read()
{
int w=1,s=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
void build(int i,int l,int r)
{
tree[i].mul=1;
tree[i].add=0;
if(l==r)
tree[i].sum=a[l];
else
{
int mid=(l+r)>>1;
build(ls(i),l,mid);
build(rs(i),mid+1,r);
tree[i].sum=tree[ls(i)].sum+tree[rs(i)].sum;
}
tree[i].sum%=p;
return;
}
void pushdown(int i,int l,int r)
{
int mid=(l+r)>>1;
tree[ls(i)].sum=(tree[ls(i)].sum*tree[i].mul+tree[i].add*(mid-l+1))%p;
tree[rs(i)].sum=(tree[rs(i)].sum*tree[i].mul+tree[i].add*(r-mid))%p;
tree[ls(i)].mul=(tree[ls(i)].mul*tree[i].mul)%p;
tree[rs(i)].mul=(tree[rs(i)].mul*tree[i].mul)%p;
tree[ls(i)].add=(tree[ls(i)].add*tree[i].mul+tree[i].add)%p;
tree[rs(i)].add=(tree[rs(i)].add*tree[i].mul+tree[i].add)%p;
tree[i].mul=1;
tree[i].add=0;
return ;
}
void mul(int i,int stdl,int stdr,int l,int r,long long k)
{
if(r<stdl||stdr<l) return ;
if(l<=stdl&&r>=stdr)
{
tree[i].sum=(tree[i].sum*k)%p;
tree[i].mul=(tree[i].mul*k)%p;
tree[i].add=(tree[i].add*k)%p;
return ;
}
pushdown(i,stdl,stdr);
int mid=(stdl+stdr)>>1;
mul(ls(i),stdl,mid,l,r,k);
mul(rs(i),mid+1,stdr,l,r,k);
tree[i].sum=(tree[ls(i)].sum+tree[rs(i)].sum)%p;
return;
}
void add(int i,int stdl,int stdr,int l,int r,long long k)
{
if(r<stdl || l>stdr)return ;
if(r>=stdr&&l<=stdl)
{
tree[i].add=(tree[i].add+k)%p;
tree[i].sum=(tree[i].sum+k*(stdr-stdl+1))%p;
return ;
}
pushdown(i,stdl,stdr);
int mid=(stdl+stdr)>>1;
add(ls(i),stdl,mid,l,r,k);
add(rs(i),mid+1,stdr,l,r,k);
tree[i].sum=(tree[ls(i)].sum+tree[rs(i)].sum)%p;
return ;
}
long long query(int i,int stdl,int stdr,int l,int r)
{
if(r<stdl||l>stdr)return 0;
if(r>=stdr&&l<=stdl) return tree[i].sum;
pushdown(i,stdl,stdr);
int mid=(stdl+stdr)>>1;
return (query(ls(i),stdl,mid,l,r)+query(rs(i),mid+1,stdr,l,r))%p;
}
int main()
{
n=read();m=read();p=read();
for(ri i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
for(ri i=1;i<=m;i++)
{
int t;
t=read();
int x,y;
long long k;
if(t==1)
{
x=read();
y=read();
scanf("%lld",&k);
mul(1,1,n,x,y,k);
}
else if(t==2)
{
x=read();
y=read();
scanf("%lld",&k);
add(1,1,n,x,y,k);
}
else
{
x=read();
y=read();
printf("%lld\n",query(1,1,n,x,y));
}
}
return 0;
}
打线段树手残了问了学长,于是有了下面这段话QAQ
调试程序的一大秘诀是打印中间值
有闲心的话去学一下gdb,虽然我没用过,但是上了大学用idea debug的时候能单步调试非常地爽(
没闲心就像我一样printf打印中间值
这次debug,第一个m是肉眼看出来的。第二个是打印中间值看出来的。打印每步过后整棵线段树的sum,add,mul, 没看出来什么问题就把每次进入query函数的参数打印出来,手动执行,然后就发现不对力
打印中间值就相当于不会用gdb的人手动模拟了一个gdb观察中间变量,永远滴神(
求区间最值
#include <stdio.h>
#include <string.h>
#define maxn 1000002
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
int T[maxn << 2];
int min(int a, int b) {
return a < b ? a : b;
}
void pushUp(int rt) {
T[rt] = min(T[rt<<1], T[rt<<1|1]);
}
void build(int l, int r, int rt) {
if(l == r) {
scanf("%d", &T[rt]);
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
pushUp(rt);
}
void update(int pos, int V, int l, int r, int rt) {
if(l == r) {
T[rt] = V;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(pos, V, lson);
else update(pos, V, rson);
pushUp(rt);
}
int query(int L, int R, int l, int r, int rt) {
if(L == l && R == r) return T[rt];
int mid = (l + r) >> 1;
if(R <= mid) return query(L, R, lson);
else if(L > mid) return query(L, R, rson);
return min(query(L, mid, lson), query(mid + 1, R, rson));
}
int main() {
int N, i, Q, a, c, b;
scanf("%d", &N);
build(1, N, 1);
scanf("%d", &Q);
while(Q--) {
scanf("%d%d%d", &c, &a, &b);
if(c) update(a, b, 1, N, 1);
else printf("%d\n", query(a, b, 1, N, 1));
}
return 0;
}
树状数组
单点修改+区间查询
#include<bits/stdc++.h>
#define ri register int
using namespace std;
int n,m;
int tree[10001000];
int lowbit(int x)
{
return x&(-x);
}
void update(int pos,int x)
{
while(pos<=n)
{
tree[pos]+=x;
pos+=lowbit(pos);
}
}
int query(int pos)
{
int ans=0;
while(pos)
{
ans+=tree[pos];
pos-=lowbit(pos);
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(ri i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
update(i,x);
}
for(ri i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x==1) update(y,z);
else printf("%d\n",query(z)-query(y-1));
}
}
区间修改+单点查询
#include<bits/stdc++.h>
#define ri register int
using namespace std;
int n,m;
long long tree[500050];
long long lowbit(int x)
{
return x&(-x);
}
void update(int pos,long long x)
{
while(pos<=n)
{
tree[pos]+=x;
pos+=lowbit(pos);
}
}
long long query(int pos) //单点询问
{
long long ans=0;
while(pos)
{
ans+=tree[pos];
pos-=lowbit(pos);
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
long long last=0; //差分值初始化
for(ri i=1;i<=n;i++)
{
long long x;
scanf("%lld",&x);
update(i,x-last);
last=x;
}
while(m--)
{
int x;
scanf("%d",&x);
if(x==1) //区间修改
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
update(l,k);
update(r+1,-k);
}
else
{
int y;
scanf("%d",&y);
printf("%lld\n",query(y));
}
}
}
区间修改+区间查询
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[50005] = {0};
int sum1[50005]; //(D[1] + D[2] + ... + D[n])
int sum2[50005]; //(1*D[1] + 2*D[2] + ... + n*D[n])
int lowbit(int x)
{
return x&(-x);
}
void updata(int i,int k)
{
int x=i;
while(i <= n)
{
sum1[i]+=k;
sum2[i]+=k*(x-1);
i+=lowbit(i);
}
}
int getsum(int i)
{ //求前缀和
int res=0, x=i;
while(i>0)
{
res+=x*sum1[i]-sum2[i];
i-=lowbit(i);
}
return res;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
updata(i,a[i]-a[i-1]);
}
int x,y,k;
cin>>x>>y>>k;
updata(x,k);
updata(y+1,-k);
int sum = getsum(y) - getsum(x-1);
return 0;
}
ST表
#include <iostream>
#include <algorithm>
using namespace std;
int a[1010];//原始输入数组
int st[1010][20];//st表
void init(int n)
{
for (int i = 0; i < n; i++)
st[i][0] = a[i];
for (int i = 1; (1 << i) <= n; i++)
{
for (int j = 0; j + (1 << i) - 1 < n; j++)
st[j][i] = min(st[j][i - 1],st[j + (1 << (i - 1))][i - 1]);
}
}
int search(int l, int r)
{
int k = (int)(log((double)(r - l + 1)) / log(2.0));
return min(st[l][k],st[r - (1 << k) + 1][k]);
}
int main()
{
int n,m;
while (cin >> n >> m)
{
for (int i = 0; i < n; i++)
cin >> a[i];
init(n);
while (m--)
{
int l, r;
cin >> l >> r;
cout << search(l,r) << endl;;
}
}
return 0;
}
树链剖分+线段树维护
众所周知,树链剖分最难的是模板题
洛谷P3384
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#define Rint register int
#define mem(a,b) memset(a,(b),sizeof(a))
#define Temp template<typename T>
using namespace std;
typedef long long LL;
Temp inline void read(T &x){
x=0;T w=1,ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
x=x*w;
}
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define len (r-l+1)
const int maxn=200000+10;
int n,m,r,mod;
int e,beg[maxn],nex[maxn],to[maxn],w[maxn],wt[maxn];
int a[maxn<<2],laz[maxn<<2];
int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn];
int res=0;
inline void add(int x,int y){
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
}
inline void pushdown(int rt,int lenn){
laz[rt<<1]+=laz[rt];
laz[rt<<1|1]+=laz[rt];
a[rt<<1]+=laz[rt]*(lenn-(lenn>>1));
a[rt<<1|1]+=laz[rt]*(lenn>>1);
a[rt<<1]%=mod;
a[rt<<1|1]%=mod;
laz[rt]=0;
}
inline void build(int rt,int l,int r){
if(l==r){
a[rt]=wt[l];
if(a[rt]>mod)a[rt]%=mod;
return;
}
build(lson);
build(rson);
a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
}
inline void query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R){res+=a[rt];res%=mod;return;}
else{
if(laz[rt])pushdown(rt,len);
if(L<=mid)query(lson,L,R);
if(R>mid)query(rson,L,R);
}
}
inline void update(int rt,int l,int r,int L,int R,int k){
if(L<=l&&r<=R){
laz[rt]+=k;
a[rt]+=k*len;
}
else{
if(laz[rt])pushdown(rt,len);
if(L<=mid)update(lson,L,R,k);
if(R>mid)update(rson,L,R,k);
a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
}
}
inline int qRange(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
res=0;
query(1,1,n,id[top[x]],id[x]);
ans+=res;
ans%=mod;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
res=0;
query(1,1,n,id[x],id[y]);
ans+=res;
return ans%mod;
}
inline void updRange(int x,int y,int k){
k%=mod;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
update(1,1,n,id[x],id[y],k);
}
inline int qSon(int x){
res=0;
query(1,1,n,id[x],id[x]+siz[x]-1);
return res;
}
inline void updSon(int x,int k){
update(1,1,n,id[x],id[x]+siz[x]-1,k);
}
inline void dfs1(int x,int f,int deep){
dep[x]=deep;
fa[x]=f;
siz[x]=1;
int maxson=-1;
for(Rint i=beg[x];i;i=nex[i]){
int y=to[i];
if(y==f)continue;
dfs1(y,x,deep+1);
siz[x]+=siz[y];
if(siz[y]>maxson)son[x]=y,maxson=siz[y];
}
}
inline void dfs2(int x,int topf){
id[x]=++cnt;
wt[cnt]=w[x];
top[x]=topf;
if(!son[x])return;
dfs2(son[x],topf);
for(Rint i=beg[x];i;i=nex[i]){
int y=to[i];
if(y==fa[x]||y==son[x])continue;
dfs2(y,y);
}
}
int main(){
read(n);read(m);read(r);read(mod);
for(Rint i=1;i<=n;i++)read(w[i]);
for(Rint i=1;i<n;i++){
int a,b;
read(a);read(b);
add(a,b);add(b,a);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
while(m--){
int k,x,y,z;
read(k);
if(k==1){
read(x);read(y);read(z);
updRange(x,y,z);
}
else if(k==2){
read(x);read(y);
printf("%d\n",qRange(x,y));
}
else if(k==3){
read(x);read(y);
updSon(x,y);
}
else{
read(x);
printf("%d\n",qSon(x));
}
}
}
DP
背包类
01背包
#include<bits/stdc++.h>
using namespace std;
int dp[100010],T,N,w[100010],t[100010];
int main()
{
cin>>T>>N;
for(int i=1;i<=N;i++)
cin>>t[i]>>w[i];
for(int i=1;i<=N;i++)
for(int j=T;j>=t[i];j--)
dp[j]=max(dp[j],dp[j-t[i]]+w[i]);
printf("%d",dp[T]);
}
完全背包(未优化)
洛谷P1616
十年OI一场空,遇见yummy见祖宗
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e4+5,M=1e7+5;
int n,m,w[N],v[N],f[M];
signed main(){
scanf("%lld%lld",&m,&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&w[i],&v[i]);
for(int i=1;i<=n;i++)
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+v[i]);
printf("%lld",f[m]);
return 0;
}
多次背包(未优化)
#include<bits/stdc++.h>
using namespace std;
int n,m,dp[100010],v[100010],w[100010],s[100010];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&v[i],&w[i],&s[i]);
for(int i=1;i<=n;i++)
for(int j=m;j>=0;j--)
for(int k=0;k<=s[i];k++)
if(k*v[i]<=j) dp[j]=max(dp[j],dp[j-k*v[i]]+w[i]*k);
printf("%d",dp[m]);
}
多重背包的二进制优化
还有一种效率更高的单调队列优化,这里不提到。
for (int i = 1; i <= spe; i++)
{
//核心代码
for (int j = 1; num[i] > j; j <<= 1)//注意j用到二进制位移
{
sale[++count] = sale[i] * j;
wei[count] = wei[i] * j;
num[i] -= j;
}
wei[i] = wei[i] * num[i];
sale[i] = sale[i] * num[i];
}
```cpp
分组背包
#include<bits/stdc++.h>
using namespace std;
int dp[100010],w[100010],c[100010],num[100010];
int main()
{
int v,n,t;
scanf("%d%d%d",&v,&n,&t);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&w[i],&c[i],&num[i]);
for(int i=1;i<=t;i++)
for(int j=v;j>=0;j--)
for(int k=1;k<=n;k++)
if(num[k]==i&&j>=w[k])dp[j]=max(dp[j],dp[j-w[k]]+c[k]);
printf("%d",dp[v]);
}
字符串
KMP
#include<bits/stdc++.h>
#define ri register int
using namespace std;
char s1[1000100],s2[1000100];
int len1,len2,j;
int kmp[1000100];
int main()
{
scanf("%s%s",s1+1,s2+1);
len1=strlen(s1+1);
len2=strlen(s2+1);
for(ri i=2;i<=len2;i++)
{
while(j&&s2[i]!=s2[j+1])
j=kmp[j];
if(s2[j+1]==s2[i]) j++;
kmp[i]=j;
}
j=0;
for(ri i=1;i<=len1;i++)
{
while(j>0&&s2[j+1]!=s1[i]) j=kmp[j];
if(s2[j+1]==s1[i]) j++;
if(j==len2)
{
printf("%d\n",i-len2+1);
j=kmp[j];
}
}
for(ri i=1;i<=len2;i++)
printf("%d ",kmp[i]);
}
数学
欧几里得算法
#include <iostream>
using namespace std;
int gcd(int a, int b)
{
if (a < b) swap(a, b);
return b == 0 ? a : gcd(b, a % b);
}
int x, y;
int main(){
cin >> x >> y;
cout << gcd(x, y);
//直接使用STL中的__gcd()同样高效
return 0;
}
埃氏筛法
#include<bits/stdc++.h>
using namespace std;
bool prime[100010];
int main()
{
int n;
cin>>n;
prime[0]=prime[1]=1;
int maxn=sqrt(n);
for(int i=2;i<=maxn;i++)
{
if(!prime[i])
for(int j=i*2;j<=n;j+=i)
prime[j]=1;
}
for(int i=1;i<=n;i++)
if(!prime[i]) cout<<i<<' ';
}
欧拉线性筛及欧拉函数
#include<bits/stdc++.h>
using namespace std;
bool isp[100010];
int pri[100010],phi[100010],cnt;
int main()
{
int n;
cin>>n;
phi[1]=isp[1]=1;
// 欧拉线性筛
for(int i=1;i<=n;i++)
{
if(!isp[i])
{
pri[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt && i*pri[j]<=n;j++)
{
isp[i*pri[j]]=1;
if(i%pri[j]) phi[i*pri[j]]=phi[i]*phi[pri[j]];
else
{
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
}
}
for(int i=1;i<=n;i++)
if(!isp[i]) cout<<i<<' ';
cout<<endl<<endl;
for(int i=1;i<=n;i++)
cout<<phi[i]<<' ';
}
求解逆元的千层套路
保证给出数据一定有逆元的时候才可以用哦
例题
扩展欧几里得
#include<bits/stdc++.h>
using namespace std;
long long a,b;
long long x,y;
void exgcd(long long a,long long b)
{
if(b==0)
{
x=1;
y=0;
return ;
}
exgcd(b,a%b);
long long temp=x;
x=y;
y=temp-a/b*y;
}
int main()
{
scanf("%d%d",&a,&b);
exgcd(a,b);
x=(x%b+b)%b;
printf("%d",x);
}
未完待续咯~