[联赛前整理] 终极必备模板

吐血了,好多。

一、基础模板

① 二维前缀和

回忆方法:画个图就懂了

延伸:最大子矩阵的方法,压行。

for(int i = 1; i <= n; i++)
{
      for(int j = 1; j <= m; j++)
      {
            int a;
            scanf("%d", &a);
            sum[i][j] = a + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1];
      }
}

② 高精度

回忆方法: 先背下来再说。。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 using namespace std;
  5 #define maxn 50001
  6 
  7 struct BigN{
  8     int num[maxn];
  9     int length;
 10     BigN(const string& x){
 11         length = x.length();
 12         for(int i=length-1,q=0; i>=0; i--,q++){
 13             num[q] = x[i] - '0'; //注意-'0' 
 14         }
 15     }
 16     BigN(){
 17         length = 0;
 18         memset(num,0,sizeof(num));
 19     }
 20     BigN operator +(const BigN& x){
 21         BigN res;
 22         res.length = max(x.length,length);
 23         for(int i=0;i<res.length;i++){
 24             res.num[i] += x.num[i] + num[i];
 25             res.num[i+1] += res.num[i]/10;
 26             res.num[i]%=10;
 27         } 
 28         if(res.num[res.length]!=0)res.length++;
 29         return res;
 30     }
 31     void pushdown(){
 32         int p=0;
 33         for(int i=length;i>=0;i--){
 34             if(num[i]!=0){
 35                 p=i;
 36                 break;
 37             }
 38         }
 39         length=p+1;
 40     }
 41     BigN operator - (const BigN& x){
 42         BigN res;
 43         res.length = max(length, x.length);
 44         for(int i=0;i<res.length;i++){
 45             res.num[i] += (num[i] - x.num[i]);
 46             if(res.num[i]<0)
 47             {
 48                 res.num[i+1]-=1;
 49                 res.num[i]+=10;
 50             }
 51         }
 52         res.pushdown();
 53         return res;
 54     }
 55     void pushup(){
 56         for(int i=0;i<length;i++){
 57             if(num[i]>9){
 58                 num[i+1] += num[i]/10;
 59                 num[i]%=10;
 60             }
 61         }
 62     } 
 63     BigN operator * (const BigN& x){
 64         BigN res;
 65         res.length = length + x.length;
 66         for(int i=0;i<length;i++){
 67             for(int j=0;j<x.length;j++){
 68                 res.num[i+j] += num[i]*x.num[j];
 69             }
 70         } 
 71         res.pushup();
 72         res.pushdown();
 73         return res;
 74     }
 75     BigN operator * (const int& x){
 76         BigN res;
 77         res.length = length+10;
 78         for(int i=0;i<length;i++){
 79             res.num[i] += num[i]*x;
 80         } 
 81         res.pushup();
 82         res.pushdown();
 83         return res;
 84     }
 85     BigN operator / (const int& x){
 86         BigN res;
 87         res.length = length;
 88         for(int i=length-1;i>=0;i--)
 89             res.num[i] = num[i];
 90         for(int i=length-1;i>=0;i--){
 91             if(i>0)res.num[i-1] += res.num[i]%x*10;
 92             res.num[i] /= x;
 93         }
 94         res.pushdown();
 95         return res;
 96     }
 97     int operator % (const int& x){
 98         int res = 0;
 99         for(int i=length-1;i>=0;i--){
100             res = (res*10 + num[i])%x;
101         }
102         return res;
103     }
104 };
105 ostream& operator<<(ostream& os,const BigN& x){
106     for(int i=x.length-1;i>=0;i--)
107         os<<x.num[i];
108     return os;
109 }
110 BigN pow(BigN b,int p){
111     BigN res(string("1"));
112     while(p>0){
113         if(p&1)res = res*b;
114         p = p>>1;
115         b = b*b;
116     }
117     return res;
118 }
119 //a*b = 最小公倍数*最大公约数 
120 BigN gcd(BigN a,BigN b){
121     //while(b^=a^=b^=a%=b);
122     while(!(b.length==0&&b.num[0]==0)){
123         a=a%b;
124         swap(a,b); 
125     }
126     return a;
127 }
128 BigN lcm(BigN a,BigN b,BigN Gcd){
129     return a*b/Gcd;
130 }
131 
132 int main(){
133     string a,b;
134     cin>>a>>b;
135     BigN ba(a),bb(b);
136     if((a.length() == b.length() && a < b) || a.length() < b.length())
137     {
138         printf("-");
139         cout<<(bb - ba);
140     }
141     else
142         cout<<(ba-bb);
143     return 0;
144 }

 

③ 快速幂 & 取模

int pow(int a, int b)
{
    int ans = 1, base = a;
    while(b != 0)
    {
        if(b & 1 != 0)
            ans *= base;
        base *= base;
        b >>= 1;
    }
    return ans;
}

int powmod(int a, int b, int c)
{
    int ans = 1, base = a % c;
    while(b != 0) 
    {
        if(b & 1 != 0)
            ans = (ans * base) % c;
        base = (base * base) % c;
        b>>=1;
    }
    return ans;
}

 

④ 并查集

 1 /*
 2 */
 3 #include<iostream>
 4 #include<cstdio>
 5 #include<cstring>
 6 using namespace std;
 7 
 8 int n, m;
 9 int par[10007];
10 void init()
11 {
12     for(int i = 1; i <= n; i++)    
13         par[i] = i;
14 }
15 int find(int x)
16 {
17     if(par[x] == x)
18         return x;
19     else
20         return par[x] = find(par[x]);
21 }
22 void merge(int x, int y)
23 {
24     int fx = find(x);
25     int fy = find(y);
26     //rank
27     if(fx == fy)
28         return;
29     else
30         par[fy] = fx;
31 }
32 bool same(int x, int y)
33 {
34     return (find(x) == find(y));
35 }
36 int main()
37 {
38     scanf("%d%d", &n, &m);
39     init();
40     for(int i = 1; i <= m; i++)
41     {
42         int z, x, y;
43         scanf("%d%d%d", &z, &x, &y);
44         if(z == 1)
45             merge(x, y);
46         else
47         {
48             if(same(x, y))
49                 printf("Y\n");
50             else
51                 printf("N\n");
52         }
53     }
54     return 0;
55 }

 

⑤ 归并排序求逆序对

初赛GG了,复赛别栽在上面。。

s即为答案

 1 void merge(int l, int m, int r)
 2 {
 3     int i = l; 
 4     int j = m + 1;
 5     int k = l;
 6     while(i <= m && j <= r)
 7     {
 8         if(a[i] > a[j])
 9         {
10             tmp[k++] = a[j++];
11             s += m - i + 1;
12         }
13         else
14         {
15             tmp[k++] = a[i++];
16         }
17     }
18     while(i <= m)
19         tmp[k++] = a[i++];
20     while(j <= r)
21         tmp[k++] = a[j++];
22     for(int p = l; p <= r; p++)
23         a[p] = tmp[p];
24 }
25 void mergesort(int l, int r)
26 {
27     if(l < r)  
28     {
29         int mid = (l + r) / 2;
30         mergesort(l, mid);
31         mergesort(mid + 1, r);
32         merge(l, mid, r);
33     }
34 }

 

⑥ 单调队列

luogu求m区间最小值(sliding window)

 1 /*
 2 */
 3 #include<iostream>
 4 #include<cstdio>
 5 #include<cstring>
 6 using namespace std;
 7 
 8 const int maxn = 2000007;
 9 int n, m, x;
10 int head = 1, tail = 1;
11 pair <int, int> q[maxn];
12 
13 int main()
14 {
15     scanf("%d%d", &n, &m);
16     int x;
17     scanf("%d", &x);
18     printf("%d\n", 0);
19     
20     q[head] = make_pair(1, x);
21     tail++;
22     
23     for(int i = 2; i <= n; i++)
24     {
25         int x;
26         scanf("%d", &x);
27         if(i - q[head].first > m) 
28             head++;//队列区间大于m,弹顶
29         printf("%d\n", q[head].second);//输出此时前m项最小
30         
31         while(tail > head && x < q[tail - 1].second)
32             tail--;
33         
34         q[tail] = make_pair(i, x);
35         tail++;
36     }
37     return 0;
38 }

 

二、数论模板

① 欧拉线性筛

for(int i = 2; i <= n; i++)
{
     if(isprime[i] == 0)    
        prime[++cnt] = i;
     for(int j = 1; prime[j] * i <= n; j++)
     {
         isprime[prime[j] * i] = 1;
         if(i % prime[j] == 0)
             break; 
     }
}

 

最大公约数

int gcd(int a, int b)
{
    if(b == 0)
        return a;
    else
        return gcd(b, a % b);
    //lcm(a,b) = a * b / gcd(a,b);
}

 扩展欧几里得(exgcd)

int d, x, y;

void exgcd(int a, int b)
{
    if(b == 0)
    {
        d = a; 
        x = 1;
        y = 0;
    }
    else
    {
        exgcd(b, a % b);
        int t = x;
        x = y;
        y = t - a/b*y;
    }
}
   

 

③ 杨辉三角(组合数)

for(int i = 1; i <= maxn; i++)
{
    c[i][0] = 1;
    c[i][i] = 1;
}
for(int i = 1; i <= maxn; i++)
{
    for(int j = 1; j < i; j++)
    {
        c[i][j] = c[i-1][j] + c[i-1][j-1];
    }
}

 

④ 乘法逆元

⑤ 欧拉函数

⑥ 费马小定理

 三、图论模板

① 图上最短路径

 SPFA

 1 bool spfa(int s)
 2 {
 3     for(int i=0;i<=n;i++){
 4         d[i]=INF;
 5         cnt[i]=0;
 6     }
 7     d[s]=0;
 8     q.push(s);
 9     cnt[s]++;
10     while(!q.empty())
11     {
12         int x=q.front();q.pop();
13         inqueue[x]=0;
14         for(int i=0;i<g[x].size();i++)
15         {
16             int v=g[x][i].to,w=g[x][i].w;
17             if(d[v] > d[x]+w)
18             {
19                 d[v]=d[x]+w;
20                 q.push(v);                
21                 if(++cnt[v]>n)return false; //判断负环
22             }
23         }
24     }
25     return true;
26 }

Dijkstra (优先队列优化)

 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 #include<functional>
 5 using namespace std;
 6 struct edge
 7 {
 8     int to,w;
 9 };
10 #define maxm 500010
11 #define maxn 10010
12 #define INF 2e9
13 typedef pair<int,int>P;
14 int n,m,s;
15 int v;
16 int d[maxn];
17 vector <edge> g[maxn];
18 
19 void dijkstra()
20 {
21     priority_queue<P,vector<P>,greater<P> >que;
22     for(int i=1;i<=n;i++)
23         d[i]=INF;
24     d[s]=0;
25     que.push(P(0,s));
26     while(!que.empty())
27     {
28         P p=que.top();que.pop();
29         int v=p.second;
30         if(d[v] < p.first)continue;
31         for(int i=0;i<g[v].size();i++)
32         {
33             edge e=g[v][i];
34             if(d[e.to] > d[v]+e.w)
35             {
36                 d[e.to]=d[v]+e.w;
37                 que.push(P(d[e.to],e.to));
38             }
39         }
40     }
41 }

Floyd (多源最短路 ) O(n3)

 1  for(int k = 1; k <= n; k++)
 2  {
 3         for(int i = 1; i <= n; i++)
 4         {
 5                for(int j = 1; j <= n; j++)
 6               {
 7                   dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
 8               }
 9         }
10  }

② 最小生成树

注意细节不能漏掉,一次为了全对也不要那么快!调起来极其麻烦!

Kruskal

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int n, m, par[5007];
 7 struct node
 8 {
 9     int u, v, w;
10     node(int u = 0, int v = 0, int w = 0): u(u), v(v), w(w) {}
11 }edge[200007];
12 bool cmp(node a, node b)
13 {
14     return a.w < b.w;
15 }
16 int find(int x)
17 {
18     if(par[x] == x)
19         return x;
20     else
21         return par[x] = find(par[x]);
22 }
23 int main()
24 {
25     scanf("%d%d", &n, &m);
26     for(int i = 1; i <= m; i++)
27     {
28         int u, v, w;
29         scanf("%d%d%d", &u, &v, &w);
30         edge[i] = node(u, v, w);
31     }
32     sort(edge + 1, edge + m + 1, cmp);
33     for(int i = 1; i <= n; i++)
34         par[i] = i;
35     int dis = 0;
36     int cnt = 0;
37     for(int i = 1; i <= m; i++)
38     {
39         int fu = find(edge[i].u);
40         int fv = find(edge[i].v);
41         if(fu != fv)
42         {
43             par[fu] = fv;
44             dis += edge[i].w;
45             cnt++;
46         }
47         if(cnt == n - 1) //edge is enough
48             break;
49     }
50     if(cnt != n - 1)
51         cout<<"orz"<<endl;
52     else
53         cout<<dis<<endl;
54     return 0;
55 }

 Prim

应用范围很广,不用非得排序(存图有限制)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn = 200007;
 6 const int inf = 2e9;
 7 int top = 0;
 8 struct edge
 9 {
10     int v, w;
11     edge *next;
12 }pool[maxn * 4], *h[maxn * 2];
13 void addedge(int u, int v, int w)
14 {
15     edge *p = &pool[++top];
16     p->v = v;
17     p->w = w;
18     p->next = h[u];
19     h[u] = p;
20 }
21 int n, m;
22 int ans = 0;
23 int dis[5007];
24 bool vis[5007];
25 void prim()
26 {
27     for(int i = 0; i <= n; i++)
28         dis[i] = inf;
29     dis[1] = 0;
30     int cnt = n;
31     while(cnt--)
32     {
33         int idx = 0;
34         for(int i = 1; i <= n; i++)
35             if(vis[i] == 0 && dis[i] < dis[idx])
36                 idx = i;
37         if(idx == 0)
38         {
39             ans = -1;
40             break;
41         }
42         ans += dis[idx];
43         vis[idx] = 1;
44         for(edge *p = h[idx]; p; p = p->next)
45         {
46             int v = p->v;
47             int w = p->w;
48             if(vis[v] == 0)
49             {
50                 dis[v] = min(dis[v], w);
51             }
52         }
53         
54     }
55 }
56 int main()
57 {
58     scanf("%d%d", &n, &m);
59     for(int i = 1; i <= m; i++)
60     {
61         int u, v, w;
62         scanf("%d%d%d", &u, &v, &w); 
63         addedge(u, v, w);
64         addedge(v, u, w);
65     }
66     prim();
67     cout<<ans<<endl;
68     return 0;
69 }

 

③ 强联通分量 Tarjan

15 void tarjan(int u) {
16     dfn[u] = low[u] = ++idx;//init
17     s[top++] = u;//压栈  
18     in_stack[u] = true;
19     for (int i = 0; i < edge[u].size();i++) {
20         int v = edge[u][i];
21         if (!dfn[v]) {//未被访问过 
22             tarjan(v);//continue
23             low[u] = min(low[u], low[v]);
24         }
25         else if (in_stack[v]) {//如果还在栈内 
26             low[u] = min(low[u], dfn[v]);
27         }
28     }
29     int size=0;
30     if (dfn[u] == low[u]) {//如果u是强联通的根 
31         do {
32             size++;
33             in_stack[s[--top]] = false;//退栈 
34         } while (s[top] != u);//走完一个环返回 
35         if(size != 1)
36             ans=min(ans,size);
37     }
38 }

④ 拓扑排序

 

⑤.1 Tarjan求版本

   树上LCA, DFS维护深度、到根节点距离等

  & ⑥ 树上倍增维护区间最大最小边

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 using namespace std;
  6 const int maxn = 30007;
  7 const int inf = 2e9;
  8 typedef long long ll;
  9 struct edge
 10 {
 11     int v, w;
 12     edge *next;
 13 }pool[maxn * 4], *h[maxn], *qy[maxn];
 14 int n, q, r, top = 0, par[maxn];
 15 int lca[maxn], s[maxn], t[maxn], pow2[40];
 16 bool vis[maxn];
 17 void addedge(int u, int v, int w)
 18 {
 19     edge *p = &pool[++top];
 20     p->v = v;
 21     p->w = w;
 22     p->next = h[u];
 23     h[u] = p;
 24 }
 25 void addquery(int u, int v, int w)
 26 {
 27     edge *p = &pool[++top];
 28     p->v = v;
 29     p->w = w;
 30     p->next = qy[u];
 31     qy[u] = p;
 32 }
 33 int find(int x)
 34 {
 35     if(par[x] == x)
 36         return x;
 37     else
 38         return par[x] = find(par[x]);
 39 }
 40 void tarjan(int u)
 41 {
 42     vis[u] = 1;
 43     for(edge *p = h[u]; p; p = p->next)
 44     {
 45         int v = p->v;
 46         if(vis[v] == 0)
 47         {
 48             tarjan(v);
 49             par[v] = u;
 50         }
 51     }
 52     for(edge *p = qy[u]; p; p = p->next)
 53     {
 54         int v = p->v;
 55         int id = p->w;
 56         if(vis[v] == 1)
 57         {
 58             lca[id] = find(v);
 59         }
 60     }
 61 }
 62 bool vv[maxn];
 63 int dep[maxn], fa[maxn], son[maxn], sze[maxn];
 64 ll dis[maxn];
 65 int par1[maxn * 4][25];
 66 int minw[maxn * 4][25];
 67 int maxw[maxn * 4][25];
 68 void dfs(int f, int u, int d)
 69 {
 70     vv[u] = 1;
 71     dep[u] = d;
 72     fa[u] = f;
 73     for(edge *p = h[u]; p; p = p->next)
 74     {
 75         int v = p->v;
 76         int w = p->w;
 77         if(v == u || v == fa[u]) continue;
 78         son[u]++;
 79         dis[v] = dis[u] + w;
 80         dfs(u, v, d + 1);
 81         sze[u] += sze[v];
 82     }
 83     
 84 }
 85 
 86 void buildST(int u)
 87 {
 88     for(int i = 1; i <= 16; i++)
 89     {
 90         if(dep[u] <= (1<<i))
 91             break;
 92         par1[u][i] = par1[par1[u][i-1]][i-1];
 93         maxw[u][i] = max(maxw[u][i-1], maxw[par1[u][i-1]][i-1]);
 94         minw[u][i] = min(minw[u][i-1], minw[par1[u][i-1]][i-1]);
 95     }
 96     for(edge *p = h[u]; p; p = p->next)
 97     {
 98         int v = p->v;
 99         int w = p->w;
100         if(v == u || v == fa[u]) continue;
101         par1[v][0] = u;
102         maxw[v][0] = w;
103         minw[v][0] = w;
104         buildST(v);
105     }
106 }
107 
108 int findmin(int u, int lca)
109 {
110     if(u == lca)
111         return inf;
112     int jump = log2(dep[u] - dep[lca]);
113     return min(minw[u][jump], findmin(par1[u][jump], lca));
114 }
115 
116 int findmax(int u, int lca)
117 {
118     if(u == lca)
119         return 0;
120     int jump = log2(dep[u] - dep[lca]);
121     return max(maxw[u][jump], findmax(par1[u][jump], lca));
122 }
123 
124 int main()
125 {
126     //freopen("bigwater.in", "r", stdin);
127     //freopen("bigwater.out", "w", stdout);
128     scanf("%d%d%d", &n, &q, &r);
129     for(int i = 1; i <= n; i++)    
130     {
131         par[i] = i;
132         sze[i] = 1;
133     }
134     for(int i = 1; i < n; i++)
135     {
136         int u, v, w;
137         scanf("%d%d%d", &u, &v, &w);
138         addedge(u, v, w);
139         addedge(v, u, w);
140     }
141     for(int i = 1; i <= q; i++)
142     {
143         scanf("%d%d", &s[i], &t[i]);
144         addquery(s[i], t[i], i);
145         addquery(t[i], s[i], i);
146     }
147     tarjan(r);
148     
149     dis[r] = 0;
150     
151     dfs(0, r, 1);
152     fa[r] = r;
153     
154     par1[r][0] = r;
155     buildST(r);
156     
157     for(int i = 1; i <= n; i++)
158         printf("%lld %d %d %d %d\n", dis[i], dep[i], fa[i], son[i], sze[i]);
159         
160     for(int i = 1; i <= q; i++)
161     {
162         printf("%d ", lca[i]);
163         ll ansd = dis[s[i]] + dis[t[i]] - 2 * dis[lca[i]];
164         int curmin = min(findmin(s[i], lca[i]), findmin(t[i], lca[i]));
165         int curmax = max(findmax(s[i], lca[i]), findmax(t[i], lca[i]));
166         printf("%lld %d %d\n", ansd, curmax, curmin);
167     }
168     return 0;
169 }

 ⑤.2 倍增求lca

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 const int maxn = 500000;
 7 int n, m, r, top = 0;
 8 
 9 struct node
10 {
11     int v;
12     node *next;
13 }pool[maxn * 4], *h[maxn * 2], *qy[maxn];
14 void addedge(int u, int v)
15 {
16     node *p = &pool[++top];
17     p->v = v;
18     p->next = h[u];
19     h[u] = p;
20 }
21 void addquery(int u, int v)
22 {
23     node *p = &pool[++top];
24     p->v = v;
25     p->next = qy[u];
26     qy[u] = p;
27 }
28 
29 int anc[maxn][20], maxw[maxn][20];
30 int dep[maxn];
31 bool vis[maxn];
32 
33 void dfs(int u)
34 {
35     vis[u] = 1;
36     for(int i = 1; i < 20; i++)
37         anc[u][i] = anc[anc[u][i-1]][i-1];
38     for(node *p = h[u]; p; p = p->next)
39     {
40         int v = p->v;
41         if(vis[v] == 0)
42         {
43             dep[v] = dep[u] + 1;
44             anc[v][0] = u;
45             dfs(v);
46         }
47     }
48 }
49 int lca(int u, int v)
50 {
51     if(dep[u] < dep[v])
52         swap(u, v);
53     for(int i = 19; i >= 0; i--) //移到同一深度 
54     {
55         if(dep[v] <= dep[anc[u][i]])
56             u = anc[u][i];
57     }
58     if(u == v) // v是u的祖先 
59         return u;
60     for(int i = 19; i >= 0; i--)
61     {
62         if(anc[u][i] != anc[v][i]) //从最大祖先开始判断 
63         {
64             u = anc[u][i]; //不相同证明还没到 
65             v = anc[v][i]; //于是继续跳 
66         }
67     }
68     return anc[u][0];
69 }
70 int main()
71 {
72     scanf("%d%d%d", &n, &m, &r);
73     for(int i = 1; i < n; i++)
74     {
75         int u, v;
76         scanf("%d%d", &u, &v);
77         addedge(u, v);
78         addedge(v, u);
79     }
80     dep[r] = 1;
81     anc[r][0] = r;
82     dfs(r);
83     for(int i = 1; i <= m; i++)
84     {
85         int a, b;
86         scanf("%d%d", &a, &b);
87         printf("%d\n", lca(a, b));
88     }
89     return 0;
90 }

 

posted @ 2017-11-06 08:51  秃猴  阅读(198)  评论(0编辑  收藏  举报