线段树、最短路径、最小生成树、并查集、二分图匹配、最近公共祖先--C++模板
线段树(区间修改,区间和):
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int c[1000000],n,m;
char s; void update(int p,int l,int r,int x,int add)
{
int m=(l+r) / 2;
if (l==r)
{
c[p]+=add;
return;
}
if (x<=m) update(p*2,l,m,x,add);
if (x>m) update(p*2+1,m+1,r,x,add);
c[p]=c[p<<1]+c[p<<1|1];
} int find(int p,int l,int r,int a,int b)
{
if (l==a && r==b) return c[p];
else
{
int m=(l+r) / 2;
if (b<=m) return find(p*2,l,m,a,b);
else if (a>m) return find(p*2+1,m+1,r,a,b);
else return find(p*2,l,m,a,m)+find(p*2+1,m+1,r,m+1,b);
}
} int main()
{
scanf("%d",&n);
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
cin>>s;
if (s=='M')
{
int x,y;
scanf("%d%d",&x,&y);
update(1,1,n,x,y);
}
if (s=='C')
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",find(1,1,n,x,y));
}
}
}
线段树(lazy):
线段树,并且单纯的线段树会超时,因为在将a到b的点全部加上c时,步骤太多,会超时。
需要优化。即lazy算法;
Lazy:
在将a~b点全部加c时,不要加到每个点,在表示区间的root结构体上增加一个inc域,将要加的值赋给这个inc域,然后就不要再往下了。
在求区间和时,将root中的inc值赋给要求的区间,并且将该节点的root置零。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#define ll long long
using namespace std;
ll a[1000005],t[5000005],n,lazy[5000005],m; ll read()
{
ll s=0;
char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9')
{
s=(s << 1) + (s << 3) +ch-'0';ch=getchar();
}
return s;
} void build(ll p,ll l,ll r)
{
if (l==r)
{
t[p]=a[l];
return;
}
ll m=(l+r)>>1;
build(p<<1,l,m);
build(p<<1|1,m+1,r);
t[p]=t[p<<1]+t[p<<1|1];
} void pushdown(ll x,ll len)
{
if (lazy[x]!=0)
{
lazy[x<<1]+=lazy[x];
lazy[x<<1|1]+=lazy[x];
t[x<<1]+=(len-len/2)*lazy[x];
t[x<<1|1]+=(len/2)*lazy[x];
lazy[x]=0;
}
} void update(ll a,ll b,ll l,ll r,ll x,ll p)
{
if (a<=l && b>=r)
{
t[p]+=(r-l+1)*x;
lazy[p]+=x;
return;
}
if (lazy[p]!=0) pushdown(p,r-l+1);
ll m=(l+r)/2;
if (b<=m) update(a,b,l,m,x,p<<1);
else if (a>m) update(a,b,m+1,r,x,p<<1|1);
else update(a,m,l,m,x,p<<1),update(m+1,b,m+1,r,x,p<<1|1);
t[p]=t[p<<1]+t[p<<1|1];
} ll find(ll a,ll b,ll l,ll r,ll p)
{
if (lazy[p]!=0) pushdown(p,r-l+1);
if (a==l && b==r) return t[p];
ll m=(l+r)/2;
if (b<=m) return find(a,b,l,m,p<<1);
else if (a>m) return find(a,b,m+1,r,p<<1|1);
else return find(a,m,l,m,p<<1)+find(m+1,b,m+1,r,p<<1|1);
} int main()
{
n=read(); m=read();
for (int i=1;i<=n;i++)
a[i]=read();
build(1,1,n);
int x,y,z;
for (int i=1;i<=m;i++)
{
x=read();
if (x==1)
{
x=read(),y=read(),z=read();
update(x,y,1,n,z,1);
}
else if (x==2)
{
y=read(),z=read();
printf("%lld\n",find(y,z,1,n,1));
}
}
}
二分图匹配:
#include <iostream>
#include <cstring>
#include <cstdio>
#define inf 1000007
using namespace std;
struct arr
{
int y, n;
}f[1000005];
int ls[1000005], n, m, tot, e, ans, link[1000005];
bool b[1000005]; void add(int x, int y)
{
f[++tot].y = y;
f[tot].n = ls[x];
ls[x] = tot;
} bool find(int x)
{
for (int i = ls[x]; i; i = f[i].n)
if (!b[f[i].y])
{
b[f[i].y] = 1;
if (!link[f[i].y] || find(link[f[i].y]))
{
link[f[i].y] = x;
return true;
}
}
return false;
} void work()
{
for (int i = 1; i <= n; i++)
{
memset(b, 0, sizeof(b));
if (find(i)) ans++;
}
} int main()
{
int x, y;
scanf("%d%d%d", &n, &m, &e);
for (int i = 1; i <= e; i++)
{
scanf("%d%d", &x, &y);
if (y > m) continue;
add(x, y);
}
work();
printf("%d", ans);
}
最小生成树:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
struct arr
{
int x,y,w;
}f[200007];
int g[5007],tot,n,m;
bool b[5007]; int cmp(arr a,arr b)
{
return a.w<b.w;
} int find(int x)
{
if (g[x]==x) return x;
g[x]=find(g[x]);
return g[x];
} int main()
{
cin>>n>>m;
int q,p,o,e=0;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&q,&p,&o);
e++;
f[e].x=q;
f[e].y=p;
f[e].w=o;
}
sort(f+1,f+e+1,cmp);
for (int i=1;i<=n;i++)
g[i]=i;
int k=0;
for (int i=1;i<=e;i++)
{
if (k==n-1) break;
if (find(g[f[i].x])!=find(g[f[i].y]))
{
k++;
tot+=f[i].w;
g[find(f[i].x)]=find(f[i].y);
}
}
if (k==n-1) printf("%d",tot);
else printf("orz");
}
最短路(spfa):
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct arr
{
int to,next,w;
}f[5000007];
int n,m,s,d[1000007],ls[1000007],str[1000007];
bool b[1000007]; void spfa()
{
for (int i=1;i<=n;i++)
d[i]=2147483647;
d[s]=0;
int head=0,tail=1;
b[s]=1;
str[1]=s;
while (head<tail)
{
head++;
int t=ls[str[head]];
while (t>0)
{
if (d[f[t].to]>d[str[head]]+f[t].w)
{
d[f[t].to]=d[str[head]]+f[t].w;
if (!b[f[t].to])
{
b[f[t].to]=1;
tail++;
str[tail]=f[t].to;
}
}
t=f[t].next;
}
b[str[head]]=0;
}
} int main()
{
scanf("%d%d%d",&n,&m,&s);
int p,q;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&q,&p,&f[i].w);
f[i].to=p;
f[i].next=ls[q];
ls[q]=i;
} spfa();
for (int i=1;i<=n;i++)
printf("%d ",d[i]);
}
并查集
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n,m,f[10007]; int find(int x)
{
if (f[x]==x) return x;
f[x]=find(f[x]);
return f[x];
} int main()
{
scanf("%d%d",&n,&m);
int q,p,z;
for (int i=1;i<=n;i++)
f[i]=i;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&z,&q,&p);
if (z==1)
{
f[find(q)]=find(p);
}
if (z==2)
{
if (find(q)==find(p)) cout<<"Y"<<endl;
else cout<<"N"<<endl;
}
}
}
KMP
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int a[1000005],b[1000005],p[1000005],n,m,next[1000005],ans;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &p[i]);
a[i - 1] = p[i] - p[i - 1];
}
for (int i = 1; i <= m; i++)
{
scanf("%d", &p[i]);
b[i - 1] = p[i] - p[i - 1];
}
int j = 0;
for (int i = 2; i < m; i++)
{
while (j > 0 && b[j + 1] != b[i]) j = next[j];
if (b[j + 1] == b[i]) j += 1;
next[i] = j;
}
j = 0;
for (int i = 1; i < n; i++)
{
while (j > 0 && b[j + 1] != a[i]) j = next[j];
if (b[j + 1] == a[i]) j += 1;
if (j == m - 1)
{
ans++;
j = next[j];
}
}
printf("%d", ans);
}
快速幂
int pow4(int a,int b)
{
int r=1,base=a;
while(b)
{
if(b&1) r*=base;
base*=base;
b>>=1;
}
return r;
}
强连通分量(tarjan):
#include <cstdio>
#include <iostream>
using namespace std;
struct arr
{
int x,y,next;
};
arr f[3000];
int ls[40000],stack[40000],belong[40000],low[40000],dfn[40000],cnt,e,n,d,tot,rd[40000],cd[40000],ans,s1,s2;
bool ins[40000]; void add(int x,int y)
{
e++;
f[e].x=x;
f[e].y=y;
f[e].next=ls[x];
ls[x]=e;
} void tarjan(int i)
{
int t=0;
int j=0;
d++;
dfn[i]=d;
low[i]=d;
tot++;
stack[tot]=i;
t=ls[i];
ins[i]=1;
while (t>0)
{
j=f[t].y;
if (dfn[j]==0)
{
tarjan(j);
if (low[i]>low[j]) low[i]=low[j];
}
else if (ins[j]&&dfn[j]<low[i]) low[i]=dfn[j];
t=f[t].next;
}
if (dfn[i]==low[i])
{
cnt++;
do
{
j=stack[tot];
ins[j]=false;
tot--;
belong[j]=cnt;
}
while (i!=j);
} } int main()
{
cin>>n;
int j;
e=0;
for (int i=1;i<=n;i++)
{
while (scanf("%d",&j)&&j!=0)
add(i,j);
}
for (int i=1;i<=n;i++)
if (dfn[i]==0) tarjan(i);
for (int i=1;i<=e;i++)
if (belong[f[i].x]!=belong[f[i].y])
{
cd[belong[f[i].x]]++;
rd[belong[f[i].y]]++;
}
ans=0;
s1=0;
s2=0;
for (int i=1;i<=cnt;i++)
{
if (rd[i]==0) {ans++; s1++;}
if (cd[i]==0) s2++;
}
cout<<ans<<endl;
if (cnt==1) {s1=0; s2=0;}
if (s1>s2) cout<<s1<<endl;
else cout<<s2<<endl;
}
最短路(floyd):
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i != j && i != k && j != k)
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
最近公共祖先(lca):
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct arr {int x,y,n;}f[60007];
int ls[30007],n,m,e,deep[30007],fa[30007][30],ans; void add(int x, int y)
{
f[++e].x = x;
f[e].y = y;
f[e].n = ls[x];
ls[x] = e;
} void dfs(int x, int la)
{
deep[x] = deep[la] + 1;
fa[x][0] = la;
for (int i = ls[x]; i ; i = f[i].n)
{
if (f[i].y != la)
{
dfs(f[i].y, x);
}
}
} int lca(int q, int p)
{
if (deep[p] < deep[q]) swap(p,q);
for (int j = 20; j >= 0; j--)
if (deep[fa[p][j]] >= deep[q])
p = fa[p][j];
if (p == q) return p;
for (int j = 20; j >= 0; j--)
if (fa[p][j] != fa[q][j])
{
p = fa[p][j], q = fa[q][j];
}
return fa[p][0];
} int main()
{
scanf("%d", &n);
int x, y;
for (int i = 1; i <= n - 1; i++)
{
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs(1, 0);
for (int j = 1; j <= 20; j++)
for (int i = 1; i <= n; i++)
fa[i][j] = fa[fa[i][j - 1]][j - 1];
scanf("%d", &m);
scanf("%d", &x);
m--;
while (m--)
{
scanf("%d", &y);
ans += deep[x] + deep[y] - deep[lca(x, y)] * 2;
x = y;
}
printf("%d", ans);
}
线段树、最短路径、最小生成树、并查集、二分图匹配、最近公共祖先--C++模板的更多相关文章
- 【BZOJ4025】二分图(线段树分治,并查集)
[BZOJ4025]二分图(线段树分治,并查集) 题面 BZOJ 题解 是一个二分图,等价于不存在奇环. 那么直接线段树分治,用并查集维护到达根节点的距离,只计算就好了. #include<io ...
- 【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)
[CF938G]Shortest Path Queries(线段树分治,并查集,线性基) 题面 CF 洛谷 题解 吼题啊. 对于每个边,我们用一个\(map\)维护它出现的时间, 发现询问单点,边的出 ...
- BZOJ 4025: 二分图 [线段树CDQ分治 并查集]
4025: 二分图 题意:加入边,删除边,查询当前图是否为二分图 本来想练lct,然后发现了线段树分治的做法,感觉好厉害. lct做法的核心就是维护删除时间的最大生成树 首先口胡一个分块做法,和hno ...
- bzoj2049 线段树 + 可撤销并查集
https://www.lydsy.com/JudgeOnline/problem.php?id=2049 线段树真神奇 题意:给出一波操作,拆边加边以及询问两点是否联通. 听说常规方法是在线LCT, ...
- BZOJ 2333 棘手的操作(离线+线段树+带权并查集)
这题搞了我一天啊...拍不出错原来是因为极限数据就RE了啊,竟然返回WA啊.我的线段树要开8倍才能过啊... 首先可以发现除了那个加边操作,其他的操作有点像线段树啊.如果我们把每次询问的联通块都放在一 ...
- Explorer(2019年牛客多校第八场E题+线段树+可撤销并查集)
题目链接 传送门 题意 给你一张无向图,每条边\(u_i,v_i\)的权值范围为\([L_i,R_i]\),要经过这条边的条件是你的容量要在\([L_i,R_i]\),现在问你你有多少种容量使得你可以 ...
- 「CF319E」Ping-Pong「线段树」「并查集」
题意 规定区间\((a,b)\)到区间\((c,d)\)有边当且仅当\(c<a<d\)或\(c<b<d\). 起初区间集合为空.有\(n\)(\(n\leq 10^5\))次操 ...
- 2019牛客暑期多校训练营(第八场) E 线段树+可撤销并查集
题目传送门 题意: 给出m条无向边,每条边都有一个$[l,r]$,意思是体积在这个范围内的人才能通过这条边,询问有多少种体积的可能性,能使人从1到n 思路:由于是无向边,1和n的连通性可以用并查集维护 ...
- 5.29 省选模拟赛 波波老师 SAM 线段树 单调队列 并查集
LINK:波波老师 LINK:同bzoj 1396 识别子串 不过前者要求线性做法 后者可以log过.实际上前者也被我一个log给水过了. 其实不算很水 我自认跑的很快罢了. 都是求经过一个位置的最短 ...
- 牛客多校第八场E Explorer(左开右闭线段树+可撤回并查集)题解
题意: 传送门 有\(n\)个点构成一个无向图,每条边有\(L_i,R_i\)表示这条边只能允许编号为\(L_i\dots R_i\)的人通过,现在问你最多有几个人能从\(1\)走到\(n\). 思路 ...
随机推荐
- UVA - 10539 Almost Prime Numbers (几乎是素数)
题意:输入两个正整数L.U(L<=U<1012),统计区间[L,U]的整数中有多少个数满足:它本身不是素数,但只有一个素因子. 分析: 1.满足条件的数是素数的倍数. 2.枚举所有的素数, ...
- HDU 5282:Senior's String
Senior's String Accepts: 30 Submissions: 286 Time Limit: 2000/1000 MS (Java/Others) Memory Limit ...
- windows LARGE_INTEGER 错误码输出格式
如果是负数,I32X 版权声明:本文为博主原创文章,未经博主允许不得转载.
- Kali桥接模式下配置静态ip
以管理员身份运行虚拟机 打开控制面板-->网络和Internet-->更改适配器 再在虚拟机处桥接到这个WLAN2 点击 编辑-->编辑虚拟网卡 没有网卡就点上图的添加网络作为桥接网 ...
- ROS常见问题(一) 安装ROS时sudo rosdep init指令报错 最全解决方法
安装ROS时sudo rosdep init指令报错: ERROR: cannot download default sources list from: https://raw.githubuser ...
- 屏幕切换 onStart() onStop() onRestart() onDestroy()
android:configChanges="orientation|keyboardHidden|screenSize" //xml文件<activity ...
- 一个简单完整的promiseDemo
想要完全理解代码,需要理解 this 和闭包的含义. Promise是什么 简单来说,Promise 主要就是为了解决异步回调的问题.用 Promise 来处理异步回调使得代码层次清晰,便于理解,且更 ...
- HTTP协议、时间戳
1.什么是HTTP协议 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议.HTTP是万维网的数据通信的 ...
- 不同的二叉搜索树&II
不同的二叉搜索树 只要求个数,递推根节点分割左右子树即可 class Solution { public int numTrees(int n) { int []dp=new int[n+1]; fo ...
- VUE中的MVVM模式
1.传统MVP模式:业务逻辑相关的控制层 M:模型层,ajax请求 V:dom层,视图 P:控制器.js代码之类的 2.MVVM MVVM模式主要操作数据层,代码减少量是MVP的30%甚至70%