自己用的图论模板
最短路
Dijkstra
//复杂度:V*V
//注意:初始化c,vis,pre,dis
// 输入c[][]的时候判断是否大于之前的值
//注意:初始化c,vis,pre,dis
// 输入c[][]的时候判断是否大于之前的值
// 建图的时候注意是什么图
const int inf = (0x7fffffff)>>1;
const int edgeNum = 205;
int c[edgeNum][edgeNum];
int dis[edgeNum];
bool vis[edgeNum];
int pre[edgeNum];
void Dijkstra(int n,int v, int *dis,int c[edgeNum][edgeNum])
{
memset(pre,0, sizeof(pre));
for(int i=0;i<n;i++){
vis[i]=0;
dis[i]=c[i][v];
if(dis[i]==inf)pre[i]=0;
else pre[i]=v;
}
vis[v]=1; int u=v;
for(int ii=1;ii<n;ii++){
int minL=inf;
for(int i=0;i<n;i++)
if(vis[i]==0&&dis[i]<minL){
u=i;
minL=dis[i];
}
vis[u]=1;
for(int i=0;i<n;i++)
if(vis[i]==0&&dis[i]>(dis[u]+c[u][i])){
dis[i]=(dis[u]+c[u][i]);
pre[i]=u;
}
}
}
//验证的打印路径
void Dijkstra()
{
for(int i=1;i<=N;i++)
{
vis[i]=0;
dis[i]=c[1][i];
if(dis[i]!=inf)pre[i]=1;
}
vis[1]=1;
for(int i=2;i<=N;i++)
{
int u=1;int minL=inf;
for(int j=1;j<=N;j++)
{
if(vis[j]==0&&dis[j]<minL)
{
minL=dis[j];
u=j;
}
}
vis[u]=1;
for(int j=1;j<=N;j++)
{
if(vis[j]==0&&(dis[j]>dis[u]+c[u][j])){
dis[j]=dis[u]+c[u][j];
pre[j]=u;
}
}
}
}
/*==================================================*\
| Dijkstra数组实现O(N^2)
| Dijkstra --- 数组实现(在此基础上可直接改为STL的Queue实现)
| lowcost[] --- beg到其他点的最近距离
| path[] -- beg为根展开的树,记录父亲结点
\*==================================================*/
| Dijkstra数组实现O(N^2)
| Dijkstra --- 数组实现(在此基础上可直接改为STL的Queue实现)
| lowcost[] --- beg到其他点的最近距离
| path[] -- beg为根展开的树,记录父亲结点
\*==================================================*/
#define INF 0x03F3F3F3F
const int N=99999999;
int path[N], vis[N];
void Dijkstra(int cost[][N], int lowcost[N], int n, int beg){
int i, j, min;
memset(vis, 0, sizeof(vis));
vis[beg] = 1;
for (i=0; i<n; i++){
lowcost[i] = cost[beg][i]; path[i] = beg;
}
lowcost[beg] = 0;
path[beg] = -1; // 树根的标
int pre = beg;
for (i=1; i<n; i++){
min = INF;
for (j=0; j<n; j++)
// 下面的加法可能导致溢出,INF不能取太大
if (vis[j]==0&&
lowcost[pre]+cost[pre][j]<lowcost[j])
{
lowcost[j] = lowcost[pre] + cost[pre][j];
path[j] = pre;
}
for (j=0; j<n; j++)
if (vis[j] == 0 && lowcost[j] < min){
min = lowcost[j]; pre = j;
}
vis[pre] = 1;
}
}
/*==================================================*\
| 二分图匹配(匈牙利算法 BFS 实现)
| INIT: g[][] 邻接矩阵 ;
| CALL: res = MaxMatch();Nx, Ny 初始化!!!
| 优点:适用于稀疏二分图,边较少,增广路较短。
| 匈牙利算法的理论复杂度是 O(VE)
\*==================================================*/
int MAXN = 1000;
int
uN, vN;
// u, v数y目,要a初始
化!!!
bool
g[MAXN][MAXN];
// g[i][j] 表示xi与yj相连
int
xM[MAXN], yM[MAXN];
// 输出量
bool
chk[MAXN];
// 辅助量检查某3轮y[v]是否被check
bool
SearchPath(
int
u){
int
v;
for
(v = 0; v < vN; v++)
if
(g[u][v] && !chk[v])
{
chk[v] =
true
;
if
(yM[v] == -1 || SearchPath(yM[v]))
{
yM[v] = u; xM[u] = v;
return
true
;
}
}
return
false
;
}
int
MaxMatch(){
int
u, ret = 0 ;
memset(xM, -1,
sizeof
(xM));
memset(yM, -1,
sizeof
(yM));
for
(u = 0; u < uN; u++)
if
(xM[u] == -1){
memset(chk,
false
,
sizeof
(chk));
if
(SearchPath(u)) ret++;
}
return
ret;
}
常见的错误:
注意的东西:
其实跟线段树的思想差不多,都是二分的思想,分治
//初始化,效率:初始化是O(n * log n + m)n是总区间,m是询问数量,每次询问的效率是O(1)
for
(i=1;i<=N;i++)
{
scanf(
"%d"
,&a[i]);
rmq1[i][0]=a[i];
rmq2[i][0]=a[i];
}
//rmq[i][j] 起e点是i长度是2^j,这a段区间的最值
DP(N);
void DP(int N)
{
int i,j,k;
for(i=1;i<= int(log(double (N))/log(2.0));i++)
for(j=1;j<=N;j++)
{
dp1[j][i]=mmax(dp1[j][i-1],dp1[j+ int(pow(2.0,i-1))][i-1]);
dp2[j][i]=mmin(dp2[j][i-1],dp2[j+ int(pow(2.0,i-1))][i-1]);
}
}
int search(int i,int j)
{
int k=(int )(log((double)(j-i+1))/log(2.0));
return mmax(dp1[i][k],dp1[j-(1<<k)+1][k])-mmin(dp2[i][k],dp2[j-(1<<k)+1][k]);
}
作用:一边寻找一边压缩路径,减少下次找的时间。
查找一颗树中某个节点的祖先,例如查找k的祖先,在不断通过父亲节点寻找祖先结束是,顺便把从k到最终祖先节点S中经过的所有节点的祖先都指向S,那么以后搜索就能把时间降低到O(1),但是如果全部都查找了,那效率就是O(n)n是节点个数
int
ancestor[large+1];
//第i个节点祖先
int
find(
int
x)
{
if
(ancestor[x]!=x)
ancestor[x]=find(ancestor[x]);
//路径压缩
return
ancestor[x];
}
-
//传统数组(共n个元素)的元素修改和连续元素求和的复杂度分别为O(1)和O(n)。树状数//组通过将线性结构转换成伪树状结构(线性结构只能逐个扫描元素,而树状结构可以实现跳跃式扫描),使得//修改和求和复杂度均为O(lgn),
//二维树状数组
#include<iostream>
using namespace std;
#define maxn 1003
using namespace std;
#define maxn 1003
int row, col, ar[Max][Max];//那个图
int lowbit(int x){
return x & (-x);
}
}
void add(int i, int j, int w){
int tmpj;
while(i <= row){
tmpj = j;
while(tmpj <= col){
ar[i][tmpj] += w;
tmpj += lowbit(tmpj);
}
i += lowbit(i);
}
}
while(i <= row){
tmpj = j;
while(tmpj <= col){
ar[i][tmpj] += w;
tmpj += lowbit(tmpj);
}
i += lowbit(i);
}
}
int sum(int i, int j){
int tmpj, ans = 0;
while(i > 0){
tmpj = j;
while(tmpj > 0){
ans += ar[i][tmpj];
tmpj -= lowbit(tmpj);
}
i -= lowbit(i);
}
return ans;
}
int main(){
int n, ord, x, y, xx, yy, w;
while(scanf("%d%d", &ord, &n) != EOF){
memset(ar, 0, sizeof(ar));
row = col = n;
while(scanf("%d", &ord) && ord != 3){
if(ord == 1){
int n, ord, x, y, xx, yy, w;
while(scanf("%d%d", &ord, &n) != EOF){
memset(ar, 0, sizeof(ar));
row = col = n;
while(scanf("%d", &ord) && ord != 3){
if(ord == 1){
scanf("%d%d%d", &x, &y, &w);
x ++, y ++; // 二维的其实下标为[1][1],这个要记得。
add(x, y, w);
}else{
scanf("%d%d%d%d", &x, &y, &xx, &yy);
x ++, y ++, xx ++, yy ++;
int ans = sum(xx, yy)-sum(x-1, yy)-sum(xx, y-1)+sum(x-1,y-1);
printf("%d\n", ans);
}
}
}
return 0;
}
x ++, y ++; // 二维的其实下标为[1][1],这个要记得。
add(x, y, w);
}else{
scanf("%d%d%d%d", &x, &y, &xx, &yy);
x ++, y ++, xx ++, yy ++;
int ans = sum(xx, yy)-sum(x-1, yy)-sum(xx, y-1)+sum(x-1,y-1);
printf("%d\n", ans);
}
}
}
return 0;
}
struct
{
int
l;
int
r;
int
col;
bool
same;
}nnode[5*maxn];
int
L,T,O;
void
buildtree(
int
left,
int
right,
int
u)
{
nnode[u].l=left;
nnode[u].r=right;
nnode[u].col=color[1];
nnode[u].same=1;
if
(left==right)
return
;
int
mid=(left+right)/2;
buildtree(left,mid,u<<1);
buildtree(mid+1,right,(u<<1)+1);
}
int
colnum;
void
getdown(
int
u)
{
int
temp=nnode[u].col;
nnode[u].same=0;
nnode[u<<1].same=1;
nnode[u<<1].col=temp;
nnode[(u<<1)+1].same=1;
nnode[(u<<1)+1].col=temp;
}
void
update(
int
left,
int
right,
int
col,
int
u)
{
if
(nnode[u].l==left&&right==nnode[u].r)
{
nnode[u].same=1;
nnode[u].col=color[col];
return
;
}
//if(color[col]==nnode[u].col)return;
if
(nnode[u].same)getdown(u);
if
(right<=nnode[u<<1].r)
{
update(left,right,col,u<<1);
}
else
if
(left>=nnode[(u<<1)+1].l)
{
update(left,right,col,(u<<1)+1);
}
else
{
update(left,nnode[u<<1].r,col,u<<1);
update(nnode[(u<<1)+1].l,right,col,(u<<1)+1);
}
nnode[u].col=nnode[u<<1].col|nnode[(u<<1)+1].col;
}
void
query(
int
l,
int
r,
int
u)
{
if
(nnode[u].same){colnum|=nnode[u].col;
return
;}
if
(nnode[u].l==l&&nnode[u].r==r)
{
colnum|=nnode[u].col;
return
;
}
if
(r<=nnode[u<<1].r)
{
query(l,r,u<<1);
}
else
if
(l>=nnode[(u<<1)+1].l)
{
query(l,r,(u<<1)+1);
}
else
{
query(l,nnode[u<<1].r,u<<1);
query(nnode[(u<<1)+1].l,r,(u<<1)+1);
}
}
//矩阵快速幂
#define
maxn 33
int
n,k,m;
struct
Matrix
{
int
data[maxn][maxn];
void
operator
=(Matrix a)
{
for
(
int
i=0;i<n;i++)
for
(
int
j=0;j<n;j++)
{
data[i][j] = a.data[i][j];
}
}
Matrix
operator
+(Matrix a)
{
Matrix c;
for
(
int
i=0;i<n;i++)
for
(
int
j=0;j<n;j++){
c.data[i][j]=data[i][j]+a.data[i][j];
c.data[i][j]%=m;
}
return
c;
}
Matrix
operator
*(Matrix a)
{
Matrix c;
for
(
int
i=0;i<n;i++)
for
(
int
j=0;j<n;j++){
int
sum=0;
for
(
int
k=0;k<n;k++){
sum+=data[i][k]*a.data[k][j];
sum%=m;
}
c.data[i][j]=sum%m;
}
return
c;
}
void
danwei()
{
for
(
int
i=0;i<n;i++)
{
for
(
int
j=0;j<n;j++)
{
if
(i==j)
data[i][j]=1;
else
data[i][j]=0;
}
}
}
}A;
Matrix Dan;
Matrix quickpow(
int
k)
{
Matrix B = A;
Matrix c = Dan;
while
(k>0)
{
if
(k&1)c = (c*B);
k=k>>1;
B=B*B;
}
return
c;
}
Matrix erfen(
int
k)
{
if
(k==1)
return
A;
if
(k%2==0)
{
return
erfen(k/2)*(Dan+quickpow(k/2));
}
return
erfen(k/2)*(Dan+quickpow(k/2))+quickpow(k);
}
//快速幂
log n 算法
long
long
quickpow(
long
long
m,
long
long
n,
long
long
k)
{
long
long
b = 1;
while
(n > 0)
{
if
(n & 1)
b = (b*m)%k;
n = n >> 1 ;
m = (m*m)%k;
}
return
b;
}
//欧拉函数 求1,2,3....n中D和n互质的个数
1:用时长
int
eula_phi(
int
n)
{
int
ans=1;
int
i;
for
(i=2;i*i<=n;i++)
if
(n%i==0)
{
n/=i;
ans*=i-1;
while
(n%i==0)
{
n/=i;
ans*=i;
}
}
if
(n>1)
ans*=n-1;
return
ans;
}
//
2:用时短
int euler_phi(int n)
{
int m=(int )sqrt(n+0.5);
long long ans=n;
for(int i=2;i<=m;i++)
{
if(n%i==0)
{
n/=i;
ans=ans*(i-1)/i;
while(n%i==0)
{
n/=i;
}
}
}
if(n>1)
ans=ans*(n-1)/n;
return ans;
}
//已验证 O(nloglogn) 打表,1~n中D的所有欧拉函数值,存储在phi[]中
void
phi_table(
int
n,
int
*phi)
{
for
(
int
i=2;i<=n;i++)phi[i]=0;
phi[1]=1;
for
(
int
i=2;i<=n;i++)
{
if
(!phi[i])
{
for
(
int
j=i;j<=n;j+=i)
{
if
(!phi[j])phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
}
//打印素数表
#define
maxn 1000
int
pri[maxn];
int p[maxn];
int k;
void
init()
{
memset(p,1,
sizeof
(p));
for
(
int
i=2;i*i<maxn;i++)
if
(p[i])
{
for
(
int
j=i<<1;j<maxn;j+=i)
p[j]=0;
}
k=0;
for
(
int
i=2;i<maxn;i++)
if
(p[i])pri[k++]=i;
}
// 排列组合模板,要用__int64。注意参数顺序!
__int64
C(
int
m,
int
n)
{
if
(m > n - m) m = n - m;
__int64
ans = 1, cou = m;
while
(cou --)
{
ans *= n --;
while
(ans % m == 0 && m > 1)
ans /= m --;
}
return
ans;
}
//打印组合数
#define
maxn 1000
int
c[maxn][maxn];
void
init()
{
for
(
int
i=0;i<maxn;i++) c[i][0]=c[i][i]=1;
for
(
int
i=2;i<maxn;i++)
for
(
int
j=1;j<i;j++)
c[i][j]=c[i-1][j-1]+c[i-1][j];
}
#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
int gcd(int x,int y)
{return x%y==0?y:gcd(y,x%y);}
int main()
{
int n,color;
while(scanf("%d%d" ,&color,&n)!=EOF)
{
if(n==0&&color==0)break ;
double c=color;
if(n==0)
{
cout<<0<<endl; continue;
}
double ans=pow(c,n);
for(int i=1;i<n;i++)
{
ans+=pow(c,gcd(i,n));
}
if(n%2==1)
ans+=n*pow(c,(n+1)/2);
else
ans+=n/2*pow(c,n/2)+n/2*pow(c,n/2+1);
ans=ans/(2*n);
printf( "%0.f\n",ans);
}
return 0;
}
参数:a,b(输入)x,y(答案存储在这里)
返回:a和b的最小公约数
相当于求a关于-b的逆元
__int64 exGcd(__int64 a,__int64 b, __int64 &x,__int64 &y){
if(b==0){
x=1;
y=0;
return a;
}
__int64 g=exGcd(b,a%b,x,y);
__int64 temp=x;
x=y;
y=temp-(a/b)*y;
return g;
}
逆元:求a/b%c?
算法:如果bc互质,则答案等于a*d%c d是b关于c的逆元
使用:a/b%c==a*k%c => b*k-c*y=1
代入exGcd(b,c,k,y)
b是被除数 c是modle k是要求的逆元 y是无关的东西
CF157E
//打印素数表和因式分解1到n(效率 是n*log(n))
#define maxn 100001//maxn是分解的最大的数
#define maxm 32 // maxm是log2(最大分解的数)
int pri[maxn];//存储质数,但是没有maxn那么多,大概1/10
int k;//记录质数的个数
struct Node//x[i][0]是存储第i个因子,x[i][1]是存储第i个因子的数量,n是因子的个数
{
int x[maxm][2];
int n;
}nnode[maxn];//每个数字所包含的因子,如12:2,3
//Node nnodenum[maxn];//记录每个数的因子的数量,如12:2,1
void init()
{
int p[maxn];
memset(p,1, sizeof(p));
for(int i=2;i*i<maxn;i++){
if(p[i])
{
nnode[i].x[nnode[i].n++][0]=i;
for(int j=i<<1;j<maxn;j+=i){
p[j]=0;
nnode[j].x[nnode[j].n++][0]=i;
}
}
}
k=0;
for(int i=2;i<maxn;i++)
if(p[i])pri[k++]=i;
for(int i=2;i<maxn;i++)
{
int temp=i;
for(int j=0;j<nnode[i].n;j++)
{
while(temp%nnode[i].x[j][0]==0)
{
temp=temp/nnode[i].x[j][0];
nnode[i].x[j][1]++;
}
}
}
}
//效率sqrt(n)*log n
#define maxn 100001//maxn是分解的最大的数
#define maxm 32 // maxm是log2(最大分解的数)
int pri[maxn];//存储质数,但是没有maxn那么多,大概1/10
int k;//记录质数的个数
struct Node//x[i][0]是存储第i个因子,x[i][1]是存储第i个因子的数量,n是因子的个数
{
int x[maxm][2];
int n;
}nnode[maxn];//每个数字所包含的因子,如12:2,3
//Node nnodenum[maxn];//记录每个数的因子的数量,如12:2,1
void init()
{
int p[maxn];
memset(p,1, sizeof(p));
for(int i=2;i*i<maxn;i++){
if(p[i])
{
nnode[i].x[nnode[i].n++][0]=i;
for(int j=i<<1;j<maxn;j+=i){
p[j]=0;
nnode[j].x[nnode[j].n++][0]=i;
}
}
}
k=0;
for(int i=2;i<maxn;i++)
if(p[i])pri[k++]=i;
for(int i=2;i<maxn;i++)
{
int temp=i;
for(int j=0;j<nnode[i].n;j++)
{
while(temp%nnode[i].x[j][0]==0)
{
temp=temp/nnode[i].x[j][0];
nnode[i].x[j][1]++;
}
}
}
}
//效率sqrt(n)*log n
struct Node//x[i][0]是存储第i个因子,x[i][1]是存储第i个因子的数量,n是因子的个数
{
int x[maxm][2];
int n;
}nnode[maxn];//每个数字所包含的因子,如12:2,3
void fenjie(int b,Node &a)//分解数字n,存储在a中a.n是因子的数量,a.x[i][0]是该因子、a.x[i][1]是因子的数量{
int x[maxm][2];
int n;
}nnode[maxn];//每个数字所包含的因子,如12:2,3
{
a.n=0;
for(int i=0;i<maxm;i++)
a.x[i][0]=a.x[i][1]=0;
for(int i=0;i<k;i++)
{
if(b%pri[i]==0){
b/=pri[i];
a.x[a.n][0]=pri[i];
a.x[a.n][1]++;
while(b%pri[i]==0)
{
a.x[a.n][1]++;
b/=pri[i];
}
a.n++;
}
}
if(b>1){
a.x[a.n][1]++;
a.x[a.n++][0]=b;
}
}
typedef __int64 LL
LL sum_dengbi(LL q,LL n) //等比是q,长度为n+1,1+q+q^2....+q^n
{
if(n==0)return (LL)1;
if(n%2==1)//奇数
return ((1+quickpow(q,(n+1)/2,mo))*sum_dengbi(q,(n)/2))%mo;
else return ((1+quickpow(q,(n)/2,mo))*sum_dengbi(q,(n-1)/2)+quickpow(q,n,mo))%mo;
}