最短路
单源最短路(1~n)
//SPFA算法
#include<bits/stdc++.h> using namespace std; const int N= 15000; struct bian{ int x,y,d,next; }; int last[N],len,d[N]; int List[N],tail,head,v[N]; bian a[210000]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x]; last[x]=len; } int main() { int n,m,x,y,c,st,ed; scanf("%d%d",&n,&m); //点,边 for(int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&c); ins(x,y,c); ins(y,x,c); } for(int i=1;i<=n;i++)d[i]=9999999999; st=1;ed=n; d[st]=0;v[st]=1; List[1]=st;head=1;tail=2; while(head!=tail){ x=List[head]; for(int k=last[x];k;k=a[k].next){ y=a[k].y; if(d[y]>d[x]+a[k].d){ d[y]=d[x]+a[k].d; if(v[y]==0){ v[y]==1; List[tail]=y; tail++; if(tail==n+1) tail=1; } } } List[head]=0; head++; if(head==n+1)head=1; v[x]=0; } printf("%d",d[n]); }
//Dijsktra裸题 忘了题号了
#include<iostream> #include<cstring> using namespace std; #define INF 0x3f3f3f3f const int N = 150; int n,m,x,y,z,p; int a[N][N],dis[N]; bool vis[N]; void dij(int x, int y) { for(int i = 1; i <= n; i++) { dis[i] = a[1][i]; //单源最短路 vis[i] = false; } vis[x] = 1; for(int i = 1; i <= n; i++){ int minn = INF; for(int j = 1; j <= n; j++){ if(!vis[j]&&dis[j]<minn){ minn = dis[j]; p = j; } } vis[p] = 1; for(int j = 1; j <= n; j++){ if(!vis[j]&&dis[p]+a[p][j]<dis[j]) dis[j] = dis[p] + a[p][j]; } } } int main() { while(cin >> n >> m){ if(n == 0 && m == 0) break; memset(a,INF,sizeof(a)); while(m--){ cin >> x >> y >> z; a[x][y] = a[y][x] = z; } dij(1,n); cout << dis[n] << endl; } return 0; }
2.快速幂和快速乘
#include<bits/stdc++.h> using namespace std; #define int long long //这样就不用每次开long long了 const int N = 100050; inline int read() { //快读 char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } inline int qpow(int a,int b,int mod){ //快速幂 for(int c = 1; ;a = a * a % mod){ if(b & 1)c = c * a % mod; if(!(b >>= 1))return c; } } inline int qmul(int a,int b,int mod){ //快速乘 for(int c = 0; ;a = (a << 1) % mod){ if(b & 1)c = (c + a) % mod; if(!(b >>= 1))return c; } } int n,m,a,b,q,c,d,r; signed t; signed main() { t = read(); for(int i = 1;i <= t; i++){ a = read();b = read();q = read(); c = read();d = read();r = read(); cout << qpow(a,b,q) << " "<< qmul(c,d,r) << endl ; } }
3.二分
int l = 1; int r = d; while (l <= r){ int mid = (l + r) / 2; if (check(mid)){ ans = mid; l = mid + 1; } else r = mid - 1; }
4.高精度
高精度减法
#include<bits/stdc++.h> using namespace std; const int N= 10500; int na[N],nb[N],nc[N]; bool bj; string a,b; int main() { cin>>a>>b; if(a.size()<b.size()||(a.size()==b.size()&&a<b)){ //我果然年少又无知…string可以直接比较大小的…(ASCII码 bj=1; swap(a,b); } for(int i=a.size();i>=1;i--)na[i]=a[a.size()-i]-'0'; for(int i=b.size();i>=1;i--)nb[i]=b[b.size()-i]-'0'; int n=max(a.size(),b.size()); for(int i = 1; i <= n; i ++){ if(na[i] < nb[i]){ na[i + 1] --; na[i] += 10; } nc[i] = na[i] - nb[i]; } while(nc[n]==0)n--; if(bj)cout<<"-"; for(int i=n;i>0;i--)cout<<nc[i]; if(n<1)cout<<"0"; }
高精度乘法
#include<iostream> #include<cstring> #define maxn 100000+10 using namespace std; int na[maxn],nb[maxn],nc[maxn]; char a[maxn],b[maxn]; void mul() { int i,j,lena,lenb; memset(na,0,sizeof(na)); memset(nb,0,sizeof(nb)); memset(nc,0,sizeof(nc)); lena=strlen(a); lenb=strlen(b); for(i=0;i<lena;i++) na[i]=a[lena-i-1]-'0'; for(i=0;i<lenb;i++) nb[i]=b[lenb-i-1]-'0'; for(i=0;i<lena;i++) for(j=0;j<lenb;j++) nc[i+j]+=na[i]*nb[j]; int max=lena+lenb; for(i=0;i<max;i++) nc[i+1]+=nc[i]/10,nc[i]%=10; while(!nc[--max]); max++; for(i=0;i<max;i++) a[i]=nc[max-i-1]+'0'; a[max]='\0'; } int main() { while(cin>>a>>b) { mul(); puts(a); } return 0; }
5.欧几里得(辗转相除)
ll gcd(ll a, ll b) { return !b ? a : gcd(b, a%b); }
6.左偏树
7.差分、前缀和
·区间修改后询问 http://oj.ipoweru.cn/problem/24200
#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 9; typedef long long lld; #define fr(i,n) for(int i = 1; i <= n; i++) int n, m, q, l, r, od; lld a[N], d[N], s[N]; int main() { scanf("%d%d%d", &n, &m, &q); fr(i,n) scanf("%lld", &a[i]); fr(i,n) d[i] = a[i] - a[i - 1]; fr(i,m) { scanf("%d%d%d", &l, &r, &od); d[r + 1] -= od; d[l] += od; } fr(i,n) a[i] = a[i - 1] + d[i]; fr(i,n) s[i] = s[i - 1] + a[i]; fr(i,q) { scanf("%d%d", &l, &r); printf("%lld\n", s[r] - s[l - 1]); } return 0; }
8.线段树
https://www.luogu.org/problem/P3372
#include<bits/stdc++.h> using namespace std; const int N = 2e5 + 5; typedef long long ll; int n,m; ll sum[N << 2],tag[N << 2]; //传上去(用儿子更新自己 ) void pushup(int u) { sum[u] = sum[u << 1] + sum[u << 1 | 1]; } void buildTree(int u, int uL, int uR) { if(uL == uR) { scanf("%lld",&sum[u]); return ; } int mid = (uL + uR) >> 1; buildTree(u << 1, uL,mid); buildTree(u << 1 | 1, mid + 1,uR); pushup(u); } void update(int u, int uL, int uR, int mx) { sum[u] += (ll)(uR - uL + 1) * mx; tag[u] += mx; //lazy tag储存的是每个叶节点的修改量,不是所有 } void pushdown(int u, int uL, int uR) { if(tag[u]){ int mid = (uL + uR) >> 1; update(u << 1, uL, mid, tag[u]); update(u << 1|1, mid + 1,uR, tag[u]); tag[u] = 0; //!!记得清空 } } void modify(int u, int uL, int uR, int mL, int mR, int mx) { if(mL <= uL && mR >= uR) {//完全覆盖 update(u,uL,uR,mx); return; } //暴 躁 y z 在 线 画 图 pushdown(u,uL,uR); int mid = (uL + uR) >> 1; if(mL <= mid) modify(u << 1, uL, mid, mL, mR, mx); if(mid < mR) modify(u << 1 | 1, mid + 1, uR, mL,mR, mx); //"更新结束后传回答案" pushup(u); } ll query(int u, int uL, int uR, int mL, int mR) { if(mL <= uL && mR >= uR) return sum[u]; pushdown(u, uL, uR); int mid = (uL + uR) >> 1; ll ans = 0; if(mL <= mid) ans += query(u << 1, uL, mid, mL, mR); if(mid < mR) ans += query(u << 1 | 1, mid + 1, uR, mL, mR); return ans; } int main() { scanf("%d%d",&n,&m); buildTree(1,1,n); while(m--){ int opt,l,r,x; scanf("%d%d%d",&opt,&l,&r); if(opt == 1){ scanf("%d",&x); modify(1,1,n,l,r,x); //添加操作 } else printf("%lld\n",query(1,1,n,l,r)); // 询问操作 } return 0; }
#include <bits/stdc++.h> using namespace std; typedef long long lld; const int N = 2e5 + 9; int n, m; // sum存区间和(该线段树维护的内容),tag是懒惰标记,注意空间开4倍 lld sum[N << 2], tag[N << 2]; // 从子节点更新当前节点维护的内容,因为是维护区间和,所以直接取子节点的值相加 // 也就是把左右儿子加给他自己 void pushup(int u) { sum[u] = sum[u << 1] + sum[u << 1 | 1]; } void buildTree(int u, int uL, int uR) { if (uL == uR) { // 如果这个节点为叶结点,处理完后应当直接返回,否则递归两个子节点 scanf("%lld", &sum[u]); // 也可以先读入到另一个数组a里,这里改写为 sum[u]=a[l]; 也是对的 return; } int mid = uL + uR >> 1; // mid计算的是区间中点,以便得到子节点的区间范围 buildTree(u << 1, uL, mid); buildTree(u << 1 | 1, mid + 1, uR); // 注意要mid+1,这样区间才不会重叠 pushup(u); } // 更新当前节点维护的内容 void update(int u, int uL, int uR, int mx) { sum[u] += (lld)(uR - uL + 1) * mx; // 区间统一+mx,因此这个节点的区间和应该再乘以它对应的区间长度 // 要注意这里的类型强转,如果不转这个中间结果可能爆int tag[u] += mx; // 懒惰标记不必再乘 } // 下传Lazy Tag void pushdown(int u, int uL, int uR) { if (tag[u]) { // 如果tag值为0就不必传 int mid = uL + uR >> 1; update(u << 1, uL, mid, tag[u]); update(u << 1 | 1, mid + 1, uR, tag[u]); tag[u] = 0; // 注意传过以后tag就归零了 } } // mL与mR是操作区间范围,mx是操作参数 void modify(int u, int uL, int uR, int mL, int mR, int mx) { // 如果这个节点的区间被完全覆盖,那么直接更新它即可 if (mL <= uL && uR <= mR) { update(u, uL, uR, mx); return; } // 否则要去更新它的子节点,更新之前先下传Lazy Tag pushdown(u, uL, uR); // 具体地看是否要更新左子节点和右子节点(有可能均要更新) int mid = uL + uR >> 1; if (mL <= mid) modify(u << 1, uL, mid, mL, mR, mx); if (mid < mR) modify(u << 1 | 1, mid + 1, uR, mL, mR, mx); // 更新结束后,再从子节点回传答案 pushup(u); } lld query(int u, int uL, int uR, int mL, int mR) { // 如果这个节点的区间被完全覆盖,那么直接返回它存储的区间和即可 if (mL <= uL && uR <= mR) return sum[u]; // 否则去看它的子节点,先下传Lazy Tag pushdown(u, uL, uR); // 具体地看询问是否要用到左子节点或右子节点(如果用不到就不会访问) int mid = uL + uR >> 1; lld sum = 0; // 因为是求区间和,所以这里对应的是求和操作 if (mL <= mid) sum += query(u << 1, uL, mid, mL, mR); if (mid < mR) sum += query(u << 1 | 1, mid + 1, uR, mL, mR); return sum; } int main() { scanf("%d%d", &n, &m); buildTree(1, 1, n); while (m--) { int opt, l, r, x; scanf("%d%d%d", &opt, &l, &r); if (opt == 1) { scanf("%d", &x); modify(1, 1, n, l, r, x); } else printf("%lld\n", query(1, 1, n, l, r)); } }
9.树状数组
//求2^k次方的值 int lowbit(int k){ return k&-k;} //求数组的和 int query(int n) { int sum=0; while(n>0){ //当n<0时结束程序 sum+=c[n]; n=n-lowbit(n); //将n的二进制表示的最后一个零删掉 } return sum; } //修改数组元素 (此为修改数组中某个数) void modify(int i,int x) { while(i<=n){ c[i]=c[i]+x; i=i+lowbit(i); } }
树状数组模板1(单点修改,区间询问)
https://www.luogu.org/problem/P3374
#include<bits/stdc++.h> using namespace std; int n,m,k,x,l,r,ord,sum,c[500050]; //求2^k次方的值 int lowbit(int k){ return k&-k;} //求数组的和 int query(int n) { int sum=0; while(n>0){ //当n<0时结束程序 sum+=c[n]; n=n-lowbit(n); //将n的二进制表示的最后一个零删掉 } return sum; } //修改数组元素 (此为修改数组中某个数) void modify(int i,int x) { while(i<=n){ c[i]=c[i]+x; i=i+lowbit(i); } } int main() { scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++){ int a; scanf("%d",&a); modify(i,a); } for(int i = 1; i <= m; i++) { //ord=1,x,k ord=2,l,r scanf("%d",&ord); if(ord == 1) { scanf("%d%d",&x,&k); modify(x,k); } else { scanf("%d%d",&l,&r); cout << query(r) - query(l - 1) << endl; } } return 0; }
树状数组模板2(区间修改,单点询问)
https://www.luogu.org/problem/P3368
(直接在上一个板子的基础上改铁定T(亲测70),考虑差分来做)
#include<bits/stdc++.h> using namespace std; const int N = 500050; int c[N], a[N], d[N]; int n, m; int lowbit(int x) {return x & (-x);} void modify(int x, int y) { while(x <= n){ c[x] += y; x += lowbit(x); } } int query(int x) { int sum = 0; while(x){ sum += c[x]; x -= lowbit(x); } return sum; } int main() { scanf("%d%d",&n, &m); for(int i = 1; i <= n; i++){ scanf("%d",&a[i]); d[i] = a[i] - a[i - 1]; //差分数组 modify(i, d[i]); } int opt, x, y, k; for(int i = 1; i <= m; i++){ scanf("%d",&opt); if(opt == 1){ scanf("%d%d%d",&x, &y, &k); modify(x, k); //差分思想 modify(y + 1, -k); } else{ scanf("%d",&x); printf("%d\n", query(x)); } } return 0; }
100.乱七八糟的东西
//重载运算符比较大小
struct node { int len; bool operator <(const node &a)const {//重载<操作符。可以对两个node使用<操作符进行比较 return len<a.len; } };