目录
16293 字
81 分钟
个人向算法模板
个人模板
敲题模板
1#include <bits/stdc++.h>2#define debug(x) { cerr << #x << " = " << x << "\n"; }3#define debugarr(x){ \4 cerr << #x << " : "; \5 for(auto v : x) \6 cerr << v << " "; \7 cerr << "\n"; \8}9#define cutline {cerr << "----------------------\n";}10using namespace std;11using i64 = long long;12using u64 = unsigned long long;13using i128 = __int128;14using ld = long double;15using db = double;16typedef pair<int, int> pii;17typedef tuple<int, int, int> piii;18typedef pair<i64, i64> pll;19typedef pair<i128, i128> pllll;20mt19937 rnd(time(0));21template<class T>22void chmax(T &a, T b)23{24 if (a < b)25 a = b;26}27template<class T>28void chmin(T &a, T b)29{30 if (a > b)31 a = b;32}33constexpr int MOD = 998244353, INF = 1e9;34void solve()35{36
37}38signed main()39{40 ios::sync_with_stdio(0);41 cin.tie(0);42 int T = 1;43 cin >> T;44 while(T--)45 solve();46}数据结构
并查集
1struct DSU2{3 vector<int> f, siz;4 DSU() {};5 DSU(int n)6 {7 init(n);8 }9 void init(int n)10 {11 f.resize(n + 1);12 iota(f.begin(), f.end(), 0);13 siz.assign(n + 1, 1);14 }15 int find(int x)16 {17 while(x != f[x])18 x = f[x] = f[f[x]];19 return x;20 }21 bool same(int x,int y)22 {23 return find(x) == find(y);24 }25 bool merge(int x,int y)26 {27 x = find(x);28 y = find(y);29 if(x == y)30 return false;31 if(siz[x] < siz[y])32 swap(x, y);33 siz[x] += siz[y];34 f[y] = x;35 return true;36 }37 int size(int x)38 {39 return siz[find(x)];40 }41};带权并查集
1struct DSU2{3 vector<int> f, siz, d;4 int mod;//mod的大小代表有几种关系5 DSU(int n,int mod_) : f(n + 1), siz(n + 1, 1), d(n + 1, 0), mod(mod_)6 {7 iota(f.begin(), f.end(), 0);8 }9 int find(int x)10 {11 if (x != f[x])12 {13 int root = find(f[x]);// 递归找根14 d[x] = (d[x] + d[f[x]]) % mod;// 核心:累加路径权值15 f[x] = root;// 路径压缩16 }17 return f[x];18 }19 // 合并 x 和 y,关系为:x -> y 的权值为 v20 // 返回值:true 表示合并成功或者已经在一个集合中且该关系v是正确的,false 表示已经在一个集合且矛盾21 bool merge(int x,int y,int v)22 {23 int rootx = find(x);24 int rooty = find(y);25 if(rootx == rooty)26 {27 int check = (d[x] - d[y] + mod) % mod;28 return check == v;29 }30 if(siz[rootx] < siz[rooty])31 {32 swap(rootx, rooty);33 v = (mod - v) % mod;34 swap(x, y);35 }36 f[rooty] = rootx;37 siz[rootx] += siz[rooty];38 d[rooty] = (d[x] - d[y] - v + mod) % mod;39 return true;40 }41 int query(int x,int y)42 {43 int rootx = find(x);44 int rooty = find(y);45 if(rootx != rooty)46 return -1;47 return (d[x] - d[y] + mod) % mod;48 }49};可撤销并查集
1struct DSU2{3 vector<int> f, siz;4 vector<pii> his;//记录历史操作,[y, x]表示y成为了x的儿子5 int part;6 DSU() {}7 DSU(int n)8 {9 init(n);10 }11 void init(int n)12 {13 f.resize(n + 1);14 iota(f.begin(), f.end(), 0);15 siz.assign(n + 1, 1);16 his.clear();17 part = n;18 }19 int find(int x)20 {21 while(x != f[x])22 x = f[x];23 return x;24 }25 bool same(int x,int y)26 {27 return find(x) == find(y);28 }29 bool merge(int x,int y)30 {31 x = find(x);32 y = find(y);33 if(x == y)34 return false;35 if(siz[x] < siz[y])36 swap(x, y);37 his.push_back({y, x});38 siz[x] += siz[y];39 f[y] = x;40 part--;41 return true;42 }43 int size(int x)44 {45 return siz[find(x)];46 }47 // 新增:撤销上一次成功的 merge 操作48 void undo()49 {50 if(his.empty())51 return;52 auto [y, x] = his.back();53 his.pop_back();54 siz[x] -= siz[y];55 f[y] = y;56 part++;57 }58 // 新增:获取当前状态(快照)59 int hissize()60 {61 return his.size();62 }63 // 新增:回滚到之前的某个快照状态64 void rollback(int tag)65 {66 while(his.size() > tag)67 undo();68 }69};Treap
1struct Treap2{3 static const int INF = 1e9;4 vector<int> val, dat, sz, cnt;5 vector<array<int,2>> ch;6 int tot, root;7 Treap() {}8 Treap(int n)9 {10 val.resize(n + 5);11 dat.resize(n + 5);12 sz.resize(n + 5);13 cnt.resize(n + 5);14 ch.resize(n + 5, {0, 0});15 tot = 0;16 root = 0;17 build();18 }19 int New(int v)20 {21 val[++tot] = v;22 dat[tot] = rand();23 sz[tot] = 1;24 cnt[tot] = 1;25 ch[tot][0] = ch[tot][1] = 0;26 return tot;27 }28 void pushup(int id)29 {30 if(!id)31 return;32 sz[id] = cnt[id] + sz[ch[id][0]] + sz[ch[id][1]];33 }34
35 void rotate(int &id,int d)36 {37 int tp = ch[id][d ^ 1];38 ch[id][d ^ 1] = ch[tp][d];39 ch[tp][d] = id;40 id = tp;41 pushup(ch[id][d]);42 pushup(id);43 }44 void build()45 {46 root = New(-INF);47 ch[root][1] = New(INF);48 pushup(root);49 }50 void insert(int &id,int v)51 {52 if(!id)53 {54 id = New(v);55 return;56 }57 if(val[id] == v)58 {59 cnt[id]++;60 }61 else62 {63 int d = (v < val[id] ? 0 : 1);64 insert(ch[id][d], v);65 if(dat[ch[id][d]] > dat[id])66 rotate(id, d ^ 1);67 }68 pushup(id);69 }70 void remove(int &id, int v)71 {72 if(!id)73 return;74 if(v == val[id])75 {76 if(cnt[id] > 1)77 {78 cnt[id]--;79 pushup(id);80 return;81 }82 else83 {84 if(ch[id][0] || ch[id][1])85 {86 if(!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]])87 {88 rotate(id, 1);89 remove(ch[id][1], v);90 }91 else92 {93 rotate(id, 0);94 remove(ch[id][0], v);95 }96 pushup(id);97 }98 else99 {100 id = 0;101 }102 return;103 }104 }105 v < val[id] ? remove(ch[id][0], v) : remove(ch[id][1], v);106 pushup(id);107 }108 //查询 M 中有多少个数比 x 小,并且将得到的答案加一。109 int getRank(int id,int v)110 {111 if(!id)112 return 1;113 if(v == val[id])114 return sz[ch[id][0]] + 1;115 else if(v < val[id])116 return getRank(ch[id][0], v);117 else118 return sz[ch[id][0]] + cnt[id] + getRank(ch[id][1], v);119 }120 //根据排名找数字121 int getVal(int id,int rank)122 {123 if(!id)124 return INF;125 if(rank <= sz[ch[id][0]])126 return getVal(ch[id][0], rank);127 if(rank <= sz[ch[id][0]] + cnt[id])128 return val[id];129 return getVal(ch[id][1],rank - sz[ch[id][0]] - cnt[id]);130 }131 //前驱(小于 x,且最大的数)。132 int getPre(int v)133 {134 int id = root,pre = -INF;135 while(id)136 {137 if(val[id] < v)138 pre = val[id], id = ch[id][1];139 else140 id = ch[id][0];141 }142 return pre;143 }144 //后继(大于 x,且最小的数)。145 int getNext(int v)146 {147 int id = root, nxt = INF;148 while(id)149 {150 if(val[id] > v)151 nxt = val[id], id = ch[id][0];152 else153 id = ch[id][1];154 }155 return nxt;156 }157};158int main()159{160 int n;161 cin >> n;162 Treap t(n);163 while(n--)164 {165 int op, x;166 cin >> op >> x;167 if(op == 1)168 t.insert(t.root, x);169 else if(op == 2)170 t.remove(t.root, x);171 else if(op == 3)172 cout << t.getRank(t.root, x) - 1<< "\n";173 else if(op == 4)174 cout << t.getVal(t.root, x + 1) << "\n";175 else if(op == 5)176 cout << t.getPre(x) << "\n";177 else178 cout << t.getNext(x) << "\n";179 }180}树状数组
1template<typename T>2struct Fenwick3{4 int n;5 vector<T> a;6 Fenwick(int n_ = 0)7 {8 init(n_);9 }10 void init(int n_)11 {12 n = n_;13 a.assign(n + 1, T{});14 }15 void add(int x,T v)16 {17 for (int i = x; i <= n;i += i & (-i))18 {19 a[i] += v;20 }21 }22 T sum(int x)23 {24 T ans{};25 for (int i = x; i > 0;i -= i & (-i))26 {27 ans += a[i];28 }29 return ans;30 }31 T rangeSum(int l,int r)32 {33 return sum(r) - sum(l - 1);34 }35 //select的功能是找到最大的位置 x,使得前缀和到x时 < k36 int select(const T &k)37 {38 int x = 0;39 T cur{};40 for (int i = 1 << __lg(n); i;i >>= 1)41 {42 if(x + i <= n && cur + a[x + i] <= k)43 {44 x += i;45 cur += a[x];46 }47 }48 return x;49 }50};线性基
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4template<class T>5void chmax(T &a, T b)6{7 if (a < b)8 a = b;9}10//i6411struct Basis12{13 vector<i64> a;// 基向量,a[i] 的最高位为 i14 vector<i64> t;// 时间戳,-1 表示空位15 bool zero = false;16 Basis()17 {18 a.resize(64, 0);19 t.resize(64, -1);//t[i] 的默认值 -1 表示该位尚未被占用20 }21 void add(i64 x, i64 y = 2e18)22 {23 for (int i = 63; i >= 0;i--)24 {25 if((x >> i) & 1)26 {27 if (y > t[i])28 {29 swap(a[i], x);30 swap(t[i], y);31 }32 x ^= a[i];33 }34 }35 if(x == 0)36 zero = true;37 }38 // 查询 x 能否由时间戳 ≥ y 的基向量表示39 bool query(i64 x, i64 y = 0)40 {41 for (int i = 63; i >= 0;i--)42 {43 if(((x >> i) & 1) && t[i] >= y)44 x ^= a[i];45 }46 return x == 0;47 }48 // 求最大异或和49 i64 getMax() {50 i64 res = 0;51 for (int i = 63; i >= 0; --i) {52 if ((res ^ a[i]) > res) // 异或后变大则采用53 res ^= a[i];54 }55 return res;56 }57 i64 getMin()58 {59 if(zero)60 return 0;61 for (int i = 0; i <= 63;i++)62 {63 if(a[i])64 return a[i];65 }66 return 0;67 }68 //求第 k 小69 i64 getkth(i64 k)70 {71 if(zero)72 {73 if(k == 1)74 return 0;75 k--;//否则,将 k 减 1,后续只考虑非零的异或和,即第 2 小对应原来的第 1 个非零数,以此类推。76 }77 vector<i64> b = a;//复制,防止修改原数组78 vector<i64> tmp;79 for (int i = 0; i <= 63;i++)80 {81 for (int j = i - 1; j >= 0;j--)82 {83 //消元过程84 if((b[i] >> j) & 1)85 b[i] ^= b[j];86
87 }88 if(b[i])//如果不为089 tmp.push_back(b[i]);90 }91 i64 cnt = tmp.size();92 if(k >= (1ll << cnt))93 return -1;94 i64 res = 0;95 for (int i = 0; i < cnt;i++)96 {97 if((k >> i) & 1)98 res ^= tmp[i];99 }100 return res;101 }102};Splay
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4struct Splay5{6 struct Node7 {8 int val, id, lazy, size;9 Node *ch[2];10 Node *parent;11 Node(int v, int idx = 0) : val(v), id(idx), lazy(0), size(1), ch{nullptr, nullptr}, parent(nullptr) {}12 };13 Node *root;14 Splay() : root(nullptr) {}15 ~Splay() { clear(root); }16 void clear(Node *t)17 {18 if(!t)19 return;20 clear(t->ch[0]);21 clear(t->ch[1]);22 delete t;23 }24 // ---------- 辅助函数 ----------25 int getpos(Node* t) const26 {27 return t->parent ? (t->parent->ch[1] == t) : 0;28 }29 void pushup(Node* t)30 {31 if(!t)32 return;33 t->size = 1;34 if(t->ch[0])35 t->size += t->ch[0]->size;36 if(t->ch[1])37 t->size += t->ch[1]->size;38 }39 //执行加法40 void applytag(Node *t, int v)41 {42 if(!t)43 return;44 t->val += v;45 t->lazy += v;46 }47 void pushdown(Node *t)48 {49 if(!t || t->lazy == 0)50 return;51 if(t->ch[0])52 applytag(t->ch[0], t->lazy);53 if(t->ch[1])54 applytag(t->ch[1], t->lazy);55 t->lazy = 0;56 }57 // ---------- 旋转与伸展 ----------58 void rotate(Node *t)59 {60 Node *q = t->parent;61 int x = !getpos(t);62 q->ch[!x] = t->ch[x];63 if(t->ch[x])64 t->ch[x]->parent = q;65 t->parent = q->parent;66 if(q->parent)67 q->parent->ch[getpos(q)] = t;68 t->ch[x] = q;69 q->parent = t;70 pushup(q);71 pushup(t);72 }73 //伸展 (splay):将指定节点通过旋转提升到根,沿途下传懒标记。74 void splay(Node *t)75 {76 vector<Node *> stk;77 for (Node *i = t; i->parent; i = i->parent)78 stk.push_back(i->parent);79 while(!stk.empty())80 {81 pushdown(stk.back());82 stk.pop_back();83 }84 pushdown(t);85 while(t->parent)//只要 t 还不是根,就继续旋转。86 {87 if(t->parent->parent)88 {89 if(getpos(t) == getpos(t->parent))90 rotate(t->parent);91 else92 rotate(t);93 }94 rotate(t);95 }96 root = t;97 }98 //分裂(split):以值 x 为界,将树分成 < x 和 >= x 两部分99 //pair第一个元素是左子树的根(值 < x),第二个元素是右子树的根(值 ≥ x)100 pair<Node*, Node*> split(Node *t, int x)101 {102 if(!t)103 return {nullptr, nullptr};104 Node *v = nullptr;105 Node *j = t;106 for (Node *i = t; i; )107 {108 pushdown(i); // 下传懒标记,确保当前值正确109 j = i;// 记录最后访问的节点110 if(i->val >= x)111 {112 v = i;// 记录第一个遇到的 ≥ x 的节点113 i = i->ch[0]; // 继续向左,寻找更小的 ≥ x 的节点114 }115 else116 {117 i = i->ch[1]; // 向右,因为当前值 < x,要找 ≥ x 只能向右118 }119 }120 splay(j);121 if(!v)//如果没找到122 return {j, nullptr};123 splay(v);124 Node *u = v->ch[0];//将 v 的左孩子 u 取出,这就是我们需要的左子树(所有 < x 的节点)125 if(u)126 {127 v->ch[0] = u->parent = nullptr;//断开 u 与 v 的连接128 pushup(v);//更新子树大小129 }130 return {u, v};131 }132 //合并(merge):要求输入的左树的最大值 < 右树的最小值,否则合并后的树会破坏 BST 结构。133 Node* merge(Node *l,Node *r)134 {135 if(!l)136 return r;137 if(!r)138 return l;139 Node *i = l;140 while(i->ch[1])141 i = i->ch[1];142 Node *ck = r;143 while(ck->ch[0])144 ck = ck->ch[0];145 assert(i->val < ck->val && "Merge precondition violated: left max >= right min");146 splay(i);147 i->ch[1] = r;148 r->parent = i;149 pushup(i);150 return i;//返回合并后的根节点151 }152 // ---------- 基本操作 ----------153 //插入154 void insert(int val, int id = 0)155 {156 Node *x = new Node(val, id);157 if(!root)158 {159 root = x;160 return;161 }162 auto [L, R] = split(root, val);163 root = merge(merge(L, x), R);164 }165 //全部清除166 void eraseAll(int val)167 {168 if(!root)169 return;170 auto [L, MR] = split(root, val);171 auto [M, R] = split(MR, val + 1);172 if(M)173 clear(M);174 root = merge(L, R);175 }176 //只删除一个177 void eraseSingle(int val)178 {179 if(!root)180 return;181 auto [L, MR] = split(root, val);182 auto [M, R] = split(MR, val + 1);183 if(M)184 {185 Node *v = M;186 Node *l = v->ch[0];187 Node *r = v->ch[1];188 if(l)189 l->parent = nullptr;190 if(r)191 r->parent = nullptr;192 delete v;193 M = merge(l, r);194 }195 root = merge(merge(L, M), R);196 }197 //查找某个数是否存在198 bool find(int val)199 {200 auto [L, R] = split(root, val);201 bool ok = false;202 if(R && R->val == val)203 ok = true;204 root = merge(L, R);205 return ok;206 }207 //查询一个数从小往大排为第几个208 int rank(int val)209 {210 auto [L, R] = split(root, val);211 int res = (L ? L->size : 0) + 1;212 root = merge(L, R);213 return res;214 }215 //查询第k小的数216 int kth(int k)217 {218 assert(root && k >= 1 && k <= root->size);219 Node *t = root;//从根节点开始220 while(t)221 {222 pushdown(t);//先调用 pushdown(t) 下传懒标记,保证左右子树的 size 和节点值准确。223 int lsz = t->ch[0] ? t->ch[0]->size : 0;//获取左子树大小224 if(k <= lsz)225 t = t->ch[0];//说明此时到左子树去找226 else if(k == lsz + 1)//说明当前节点 t 就是第 k 小的节点。227 {228 splay(t);229 return t->val;230 }231 else//在右子树,相应的去找就行232 {233 k -= lsz + 1;234 t = t->ch[1];235 }236 }237 return -1;//一般不可能在这里return,while循环里就return完了238 }239 //返回整个树的大小240 int size() const241 {242 return root ? root->size : 0;243 }244 // //区间加法245 // //这里l ,r代表的是真实数值,不是下标246 // void rangeAdd(int l, int r, int delta)247 // {248 // if(l > r)249 // return;250 // auto [L, MR] = split(root, l);251 // auto [M, R] = split(MR, r + 1);252 // if(M)253 // applytag(M, delta);//将 M 根节点的值增加 delta(t->val += delta)。并将 M 根节点的懒标记累加 delta(t->lazy += delta)。254 // root = merge(merge(L, M), R);//复原255 // }256 //做中序遍历257 void inOrder(Node *t, vector<int> &out)258 {259 if(!t)260 return;261 pushdown(t);262 inOrder(t->ch[0], out);263 out.push_back(t->val);264 inOrder(t->ch[1], out);265 }266 //对所有> x的执行add操作267 // >= x的情况自己微调268 void add(int x, int addval)269 {270 auto [L, MR] = split(root, x);271 auto [M, R] = split(MR, x + 1);272 if(R)273 applytag(R, x);274
275 root = merge(merge(L, M), R);276 }277 //这个是special Add,在一组数插入之前就执行add,add 那些>=x的树完再插入278 void spe(int x, int id)279 {280 auto [L, R] = split(root, x);281 if(R)282 applytag(R, x);283 Node *node = new Node(x, id);284 Node *Lnode = merge(L, node);285 root = merge(Lnode, R);286
287 splay(node);288 }289 //对所有< x的执行minus操作290 void minus(int x,int mival)291 {292 auto [L, R] = split(root, x);293 if(L)294 applytag(L, -mival);295 root = merge(L, R);296 }297 void print()298 {299 vector<int> vals;300 inOrder(root, vals);301 for(int v : vals)302 cout << v << " ";303 cout << "\n";304 }305 void debugPrint()306 {307 vector<int> vals;308 inOrder(root, vals);309 for(int v : vals)310 cerr << v << " ";311 cerr << "\n";312 }313};ST表
1//1.求区间最大值 (Max)2// STable st_max(a, [](int x, int y) { return max(x, y); });3// 2. 求区间最小值 (Min)4// 3. 求区间最大公约数 (GCD)5//4. 求区间按位与 (Bitwise AND)6// 5. 求区间按位或 (Bitwise OR)7// ST 表能够工作的一个绝对前提是,操作必须满足可重复贡献性质(Idempotence)。8template<typename T, typename F>9struct STable10{11 int n;12 int maxlog;13 F func;14 // st[i][j] 表示从 i 开始,长度为 2^j 的区间内的最大值15 vector<vector<T>> st;16 //a 1 - index17 STable(const vector<T>& a,const F& f) : func(f)18 {19 n = a.size() - 1;//a[0]废弃了,size - 120 // __lg(x) 是编译器内置函数,用来求 x 最高位 1 的索引,等价于向下取整的 log2(x)21 maxlog = __lg(n) + 1;22 st.assign(n + 1, vector<T>(maxlog));23 for (int i = 1; i <= n;i++)24 st[i][0] = a[i];25 for (int j = 1; j < maxlog;j++)26 {27 int len = 1 << (j - 1);//小区间的长度28 for (int i = 1;i <= n - (1 << j) + 1;i++)29 st[i][j] = func(st[i][j - 1], st[i + len][j - 1]);//由i的两个子区间合并上来30 }31 }32 inline T query(int l,int r) const33 {34 if (l > r)35 swap(l, r);36 int k = __lg(r - l + 1);37 return func(st[l][k], st[r - (1 << k) + 1][k]);38 }39};虚树
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4
5struct VirtualTree6{7 int n;8 vector<vector<int>> adj;9 vector<int> dfn, dep;10 vector<vector<int>> st;11 int timer;12
13 vector<vector<int>> vtadj;14 vector<int> vtnodes;15
16 VirtualTree(int n_) : n(n_)17 {18 adj.resize(n + 1);19 vtadj.resize(n + 1);20 dfn.resize(n + 1, 0);21 dep.resize(n + 1, 0);22 st.assign(20, vector<int>(n + 1, 0));23 timer = 0;24 }25
26 void addEdge(int u, int v)27 {28 adj[u].push_back(v);29 adj[v].push_back(u);30 }31
32 void dfs(int u, int p, int d)33 {34 dfn[u] = ++timer;35 dep[u] = d;36 st[0][u] = p;37 for (int i = 1; i < 20;i++)38 st[i][u] = st[i - 1][st[i - 1][u]];39 for(int v : adj[u])40 {41 if(v != p)42 dfs(v, u, d + 1);43 }44 }45
46 void init(int root = 1)47 {48 dfs(root, 0, 1);49 }50
51 int getLCA(int u, int v)52 {53 if(dep[u] < dep[v])54 swap(u, v);55 for (int i = 19; i >= 0; i--)56 {57 if(dep[st[i][u]] >= dep[v])58 u = st[i][u];59 }60
61 if(u == v)62 return u;63
64 for (int i = 19; i >= 0;i--)65 {66 if(st[i][u] != st[i][v])67 {68 u = st[i][u];69 v = st[i][v];70 }71 }72 return st[0][u];73 }74
75 int build(vector<int> nodes)76 {77 if(nodes.empty())78 return 0;79 sort(nodes.begin(), nodes.end(), [&](int u, int v)80 { return dfn[u] < dfn[v]; });81
82 int k = nodes.size();83 for (int i = 0; i < k - 1;i++)84 nodes.push_back(getLCA(nodes[i], nodes[i + 1]));85
86 sort(nodes.begin(), nodes.end(), [&](int u, int v)87 { return dfn[u] < dfn[v]; });88
89 nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end());90
91 vtnodes = nodes;92
93 for (int i = 1; i < nodes.size();i++)94 {95 int p = getLCA(nodes[i - 1], nodes[i]);96 vtadj[p].push_back(nodes[i]);97 }98
99 return nodes[0];100 }101
102 void clear()103 {104 for(int u : vtnodes)105 vtadj[u].clear();106 vtnodes.clear();107 }108};李超线段树
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4using db = double;5
6struct Line7{8 db k, b;9 int id;10};11
12struct LiChaoTree13{14 int n;15 vector<int> tree;16 vector<Line> lines;17 LiChaoTree(int n_) : n(n_), tree(4 * n_ + 1, 0), lines(1, {0, 0, 0}) {}18
19 db calc(int id, int x)20 {21 if(!id)22 return 0;23 return lines[id].k * x + lines[id].b;24 }25
26 int cmp(db x, db y)27 {28 const db EPS = 1e-9;29 if(x - y > EPS)30 return 1;31 if(y - x > EPS)32 return -1;33 return 0;34 }35
36 void addLine(int x0, int y0, int x1, int y1, int id)37 {38 if(x0 > x1)39 {40 swap(x0, x1);41 swap(y0, y1);42 }43
44 db k, b;45 if(x0 == x1)46 {47 k = 0;48 b = max(y0, y1);49 }50 else51 {52 k = 1. * (y1 - y0) / (x1 - x0);53 b = y0 - k * x0;54 }55 lines.push_back({k, b, id});56 insert(1, 1, n, x0, x1, id);57 }58
59 void insert(int p, int l, int r,int x, int y, int u)60 {61 if(x <= l && r <= y)62 {63 int &v = tree[p];64 int m = l + r >> 1;65 if(!v)66 {67 v = u;68 return;69 }70
71 int fm = cmp(calc(u, m), calc(v, m));72 if(fm == 1 || (fm == 0 && u < v))73 {74 swap(u, v);75 }76
77 if(l == r || !u)78 return;79
80 int fl = cmp(calc(u, l), calc(v, l));81 if(fl == 1 || (fl == 0 && u < v))82 insert(p << 1, l, m, x, y, u);83 else84 insert(p << 1 | 1, m + 1, r, x, y, u);85 return;86 }87 int m = l + r >> 1;88 if(x <= m)89 insert(p << 1, l, m, x, y, u);90 if(y >= m + 1)91 insert(p << 1 | 1, m + 1, r, x, y, u);92 }93
94 int query(int p, int l, int r, int x)95 {96 if(l == r)97 return tree[p];98 int m = l + r >> 1;99 int ans = tree[p];100 int sub = 0;101
102 if(x <= m)103 sub = query(p << 1, l, m, x);104 else105 sub = query(p << 1 | 1, m + 1, r, x);106 if(!ans)107 return sub;108 if(!sub)109 return ans;110
111 int flag = cmp(calc(ans, x), calc(sub, x));112 if(flag == -1 || (flag == 0 && sub < ans))113 return sub;114 return ans;115 }116
117 int query(int x)118 {119 return query(1, 1, n, x);120 }121};线段树 基础区间加乘
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4int P = 998244353;5struct SegmentTree6{7 int n;8 vector<int> mulTag, addTag, sum;9 SegmentTree(int n_) : n{n_}, mulTag(4 * n + 1, 1), addTag(4 * n + 1, 0), sum(4 * n + 1) {}10 void pull(int p)11 {12 sum[p] = (sum[2 * p] + sum[2 * p + 1]) % P;13 }14 void mul(int p,int v)15 {16 mulTag[p] = 1ll * mulTag[p] * v % P;17 addTag[p] = 1ll * addTag[p] * v % P;18 sum[p] = 1ll * sum[p] * v % P;19 }20 void push(int p,int l,int r)21 {22 if(mulTag[p] != 1)23 {24 mul(2 * p, mulTag[p]);25 mul(2 * p + 1,mulTag[p]);26 mulTag[p] = 1;27 }28 if(addTag[p] != 0)29 {30 int m = l + (r - l) / 2;31 applyAdd(2 * p, l, m, addTag[p]);32 applyAdd(2 * p + 1, m + 1, r, addTag[p]);33 addTag[p] = 0;34 }35 }36 int rangeQuery(int p,int l,int r,int x,int y)37 {38 if(l > y || r < x)39 return 0;40 if(l >= x && r <= y)41 return sum[p];42 int m = l + (r - l) / 2;43 push(p, l, r);44 return (rangeQuery(2 * p, l, m, x, y) % P + rangeQuery(2 * p + 1, m + 1, r, x, y) % P);45 }46 int rangeQuery(int x,int y)47 {48 return rangeQuery(1, 1, n, x, y) % P;49 }50 void rangeMul(int p,int l,int r,int x,int y,int v)51 {52 if(l > y || r < x)53 return;54 if(l >= x && r <= y)55 return mul(p, v);56 int m = l + (r - l) / 2;57 push(p, l, r);58 rangeMul(2 * p, l, m, x, y, v);59 rangeMul(2 * p + 1, m + 1, r, x, y, v);60 pull(p);61 }62 void rangeMul(int x,int y,int v)63 {64 rangeMul(1, 1, n, x, y, v);65 }66 void applyAdd(int p,int l,int r,int v)67 {68 addTag[p] = (1ll * addTag[p] + 1ll * v) % P;69 sum[p] = (1ll * sum[p] + 1ll * (r - l + 1) * v) % P;70 }71 void rangeAdd(int p,int l,int r,int x,int y,int v)72 {73 if(l > y || r < x)74 return;75 if(l >= x && r <= y)76 {77 applyAdd(p, l, r, v);78 return;79 }80 int m = l + (r - l) / 2;81 push(p, l, r);82 rangeAdd(2 * p, l, m, x, y, v);83 rangeAdd(2 * p + 1, m + 1, r, x, y, v);84 pull(p);85 }86 void rangeAdd(int x,int y,int v)87 {88 rangeAdd(1, 1, n, x, y, v);89 }90};树链剖分
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4
5constexpr int P = 998244353;6struct SegmentTree7{8 int n;9 vector<i64> sum, lazy;10
11 SegmentTree(int n_) : n(n_), sum(4 * n + 1, 0), lazy(4 * n + 1, 0){}12
13 void pull(int p)14 {15 sum[p] = (sum[p << 1] + sum[p << 1 | 1]) % P;16 }17
18 void apply(int p, int l, int r, i64 v)19 {20 sum[p] = (sum[p] + v * (r - l + 1)) % P;21 lazy[p] = (lazy[p] + v) % P;22 }23
24 void push(int p, int l, int r)25 {26 if(lazy[p])27 {28 int m = l + r >> 1;29 apply(p << 1, l, m, lazy[p]);30 apply(p << 1 | 1, m + 1, r, lazy[p]);31 lazy[p] = 0;32 }33 }34
35 void build(int p, int l, int r, const vector<i64> &a)36 {37 if(l >= r)38 {39 sum[p] = a[l] % P;40 return;41 }42
43 int m = l + r >> 1;44 build(p << 1, l, m, a);45 build(p << 1 | 1, m + 1, r, a);46 pull(p);47 }48
49 void build(const vector<i64> &a)50 {51 build(1, 1, n, a);52 }53
54 void rangeAdd(int p, int l, int r, int x, int y, i64 v)55 {56 if(l > y || r < x)57 return;58 if(l >= x && r <= y)59 {60 apply(p, l, r, v);61 return;62 }63 push(p, l, r);64 int m = l + r >> 1;65 rangeAdd(p << 1, l, m, x, y, v);66 rangeAdd(p << 1 | 1, m + 1, r, x, y, v);67 pull(p);68 }69
70 void rangeAdd(int x, int y, i64 v)71 {72 v %= P;73 rangeAdd(1, 1, n, x, y, v);74 }75
76 i64 rangeQuery(int p,int l, int r, int x, int y)77 {78 if(l > y || r < x)79 return 0;80 if(l >= x && r <= y)81 return sum[p];82 push(p, l, r);83 int m = r + l >> 1;84 return (rangeQuery(p << 1, l, m, x, y) + rangeQuery(p << 1 | 1, m + 1, r, x, y)) % P;85 }86
87 i64 rangeQuery(int x,int y)88 {89 return rangeQuery(1, 1, n, x, y) % P;90 }91};92
93struct HLD94{95 int n, root, timer;96 vector<vector<int>> adj;97 vector<int> sz, dep, fa, son, top, dfn, rnk;98 vector<i64> val, mapped_val;99 SegmentTree seg;100
101 HLD(int n_, int r_) : n(n_), root(r_), timer(0), adj(n_ + 1), sz(n_ + 1, 0), dep(n_ + 1, 0), fa(n_ + 1, 0), son(n_ + 1, 0), top(n_ + 1, 0), dfn(n_ + 1, 0), rnk(n_ + 1, 0), val(n_ + 1, 0), mapped_val(n_ + 1, 0), seg(n_) {}102
103 void addEdge(int u, int v)104 {105 adj[u].push_back(v);106 adj[v].push_back(u);107 }108
109 void dfs1(int u, int p, int d)110 {111 dep[u] = d;112 fa[u] = p;113 sz[u] = 1;114 int max_sz = -1;115 for(int v : adj[u])116 {117 if(v == p)118 continue;119 dfs1(v, u, d + 1);120 sz[u] += sz[v];121 if(sz[v] > max_sz)122 {123 max_sz = sz[v];124 son[u] = v;125 }126 }127 }128
129 void dfs2(int u, int t)130 {131 dfn[u] = ++timer;132 rnk[timer] = u;133 top[u] = t;134 mapped_val[timer] = val[u];135 if(!son[u])136 return;137 dfs2(son[u], t);138
139 for(int v : adj[u])140 {141 if (v != fa[u] && v != son[u])142 dfs2(v, v);143 }144 }145
146 void init()147 {148 dfs1(root, 0, 1);149 dfs2(root, root);150 seg.build(mapped_val);151 }152
153 int getLCA(int u, int v)154 {155 while (top[u] != top[v])156 {157 if (dep[top[u]] < dep[top[v]]) swap(u, v);158 u = fa[top[u]];159 }160 return dep[u] < dep[v] ? u : v;161 }162
163 void modifyPath(int u, int v, i64 w)164 {165 w %= P;166 while(top[u] != top[v])167 {168 if(dep[top[u]] < dep[top[v]])169 swap(u, v);170 seg.rangeAdd(dfn[top[u]], dfn[u], w);171 u = fa[top[u]];172 }173
174 if(dep[u] > dep[v])175 swap(u, v);176 seg.rangeAdd(dfn[u], dfn[v], w);177 }178
179 i64 queryPath(int u, int v)180 {181 i64 res = 0;182 while(top[u] != top[v])183 {184 if(dep[top[u]] < dep[top[v]])185 swap(u, v);186 res = (res + seg.rangeQuery(dfn[top[u]], dfn[u])) % P;187 u = fa[top[u]];188 }189
190 if(dep[u] > dep[v])191 swap(u, v);192 res = (res + seg.rangeQuery(dfn[u], dfn[v])) % P;193 return res;194 }195
196 void modifySubtree(int u, i64 w)197 {198 w %= P;199 seg.rangeAdd(dfn[u], dfn[u] + sz[u] - 1, w);200 }201
202 i64 querySubtree(int u)203 {204 return seg.rangeQuery(dfn[u], dfn[u] + sz[u] - 1);205 }206};线段树区间最大最小值
1#include<iostream>2using namespace std;3int n, m;4struct ty {5 int maxn, minn, num;6}tree[4000010];7int a[1000010];8void build(int p,int l,int r) {9 if (l == r) {10 tree[p].maxn = a[l];11 tree[p].minn = a[l];12 tree[p].num = 1;13 return;14 }15 int mid = (l + r) / 2;16 build(2 * p, l, mid);17 build(2 * p + 1, mid + 1, r);18 tree[p].maxn = max(tree[2 * p].maxn, tree[2 * p + 1].maxn);19 tree[p].minn = min(tree[2 * p].minn, tree[2 * p + 1].minn);20 tree[p].num = tree[2 * p].num + tree[2 * p + 1].num;21}22int find(int p,int l,int r,int x) {23 if (l == r) {24 return l;25 }26 int mid = (l + r) / 2;27 if (tree[2 * p].num >= x)return find(2 * p, l, mid, x);28 else return find(2 * p + 1, mid + 1, r, x - tree[2 * p].num);29}30void del(int p,int l,int r,int x) {31 if (l == r) {32 tree[p].maxn = -1e9 - 10;33 tree[p].minn = 1e9 + 10;34 tree[p].num = 0;35 return;36 }37 int mid = (l + r) / 2;38 if (x <= mid)del(2 * p, l, mid, x);39 else del(2 * p + 1, mid + 1, r, x);40 tree[p].maxn = max(tree[2 * p].maxn, tree[2 * p + 1].maxn);41 tree[p].minn = min(tree[2 * p].minn, tree[2 * p + 1].minn);42 tree[p].num = tree[2 * p].num + tree[2 * p + 1].num;43}44ty cal(int p, int l, int r, int x, int y) {45 if (x <= l && r <= y) {46 return tree[p];47 }48 int mid = (l + r) / 2;49 if (y <= mid)return cal(2 * p, l, mid, x, y);50 if (x >= mid + 1)return cal(2 * p + 1, mid + 1, r, x, y);51 ty t1= cal(2 * p, l, mid, x, y);52 ty t2= cal(2 * p + 1, mid + 1, r, x, y);53 t1.maxn = max(t1.maxn, t2.maxn);54 t1.minn = min(t1.minn, t2.minn);55 return t1;56}57int main() {58 ios::sync_with_stdio(false);59 cin.tie(0);60 cin >> n >> m;61 for (int i = 1; i <= n; ++i)cin >> a[i];62 build(1, 1, n);63 for (int i = 1; i <= m; ++i) {64 int op, x, y;65 cin >> op;66 if (op == 1) {67 cin >> x;68 x = find(1, 1, n, x);69 del(1, 1, n, x);70 }71 else {72 cin >> x >> y;73 x = find(1, 1, n, x);74 y = find(1, 1, n, y);75 ty tem = cal(1, 1, n, x, y);76 cout << tem.minn << " " << tem.maxn << endl;77 }78 }79}线段树区间平方和
1#include<iostream>2using namespace std;3#define ll long long4int n, m;5ll a[10040];6ll sum1[40040];7ll sum2[40040];8ll lazy1[40040];9ll lazy2[40040];10void build(int p, int l, int r) {11 if (l == r) {12 sum1[p] = a[l];13 sum2[p] = a[l] * a[l];14 return;15 }16 int mid = (l + r) / 2;17 build(2 * p, l, mid);18 build(2 * p + 1, mid + 1, r);19 sum1[p] = sum1[2 * p] + sum1[2 * p + 1];20 sum2[p] = sum2[2 * p] + sum2[2 * p + 1];21}22void push(int p, int l, int r) {23 int mid = (l + r) / 2;24 lazy1[2 * p] *= lazy1[p];25 sum1[2*p] *= lazy1[p];26 sum2[2*p] *= lazy1[p] * lazy1[p];27 lazy2[2 * p] += lazy2[p];28 sum2[2*p] += (mid - l + 1) * lazy2[p] * lazy2[p] + 2 * sum1[2*p] * lazy2[p];29 sum1[2*p] += lazy2[p]*(mid-l+1);30 lazy1[2 * p + 1] *= lazy1[p];31 sum1[2 * p + 1] *= lazy1[p];32 sum2[2 * p + 1] *= lazy1[p] * lazy1[p];33 lazy2[2 * p + 1] += lazy2[p];34 sum2[2 * p + 1] += (r - (mid + 1) + 1) * lazy2[p] * lazy2[p] + 2 * sum1[2*p+1] * lazy2[p];35 sum1[2 * p + 1] += lazy2[p]*(r-(mid+1)+1);36 lazy1[p] = 1, lazy2[p] = 0;37}38void change1(int p, int l, int r, int x, int y, int num) {39 if (x <= l && r <= y) {40 lazy1[p] *= num;41 lazy2[p] *= num;42 sum1[p] *= num;43 sum2[p] *= num * num;44 return;45 }46 push(p,l,r);47 int mid = (l + r) / 2;48 if (x <= mid)change1(2*p, l, mid, x, y, num);49 if (y >= mid + 1)change1(2*p+1, mid + 1, r, x, y, num);50 sum1[p] = sum1[2 * p] + sum1[2 * p + 1];51 sum2[p] = sum2[2 * p] + sum2[2 * p + 1];52}53void change2(int p, int l, int r, int x, int y, int num) {54 if (x <= l && r <= y) {55 lazy2[p] += num;56 sum2[p] += (r - l + 1) * num * num + 2 * sum1[p] * num;57 sum1[p] += num * (r - l + 1);58 return;59 }60 push(p, l, r);61 int mid = (l + r) / 2;62 if (x <= mid)change2(2*p, l, mid, x, y, num);63 if (y >= mid + 1)change2(2*p+1, mid + 1, r, x, y, num);64 sum1[p] = sum1[2 * p] + sum1[2 * p + 1];65 sum2[p] = sum2[2 * p] + sum2[2 * p + 1];66}67
68ll cal1(int p, int l ,int r, int x, int y) {69 if (x <= l && r <= y) {70 return sum1[p];71 }72 push(p,l,r);73 int mid = (l + r) / 2;74 ll ans = 0;75 if (x <= mid)ans += cal1(2*p, l, mid, x, y);76 if (y >= mid + 1)ans += cal1(2*p+1, mid + 1, r, x, y);77 return ans;78}79ll cal2(int p, int l, int r, int x, int y) {80 if (x <= l && r <= y) {81 return sum2[p];82 }83 push(p, l, r);84 int mid = (l + r) / 2;85 ll ans = 0;86 if (x <= mid)ans += cal2(2*p, l, mid, x, y);87 if (y >= mid + 1)ans += cal2(2*p+1, mid + 1, r, x, y);88 return ans;89}90int main() {91 for (int i = 1; i <= 40000; ++i)lazy1[i] = 1, lazy2[i] = 0;92 cin >> n >> m;93 for (int i = 1; i <= n; ++i)cin >> a[i];94 build(1, 1, n);95 for (int i = 1; i <= m; ++i) {96 int op, l, r, x;97 cin >> op;98 if (op == 1) {99 cin >> l >> r;100 cout << cal1(1,1,n,l, r) << endl;101 }102 else if (op == 2) {103 cin >> l >> r;104 cout << cal2(1,1,n,l, r) << endl;105 }106 else if (op == 3) {107 cin >> l >> r >> x;108 change1(1, 1, n, l, r, x);109 }110 else {111 cin >> l >> r >> x;112 change2(1, 1, n, l, r, x);113 }114 }115}最近公共祖先
1 int n, m, s;2 cin >> n >> m >> s;3 vector<vector<int>> adj(n + 1);4 vector<vector<int>> fa(n + 1, vector<int>(32, 0));5 vector<int> dep(n + 1, 0);6 for (int i = 1; i < n;i++)7 {8 int u, v;9 cin >> u >> v;10 adj[u].push_back(v);11 adj[v].push_back(u);12 }13 auto dfs = [&](auto self, int u, int pa) -> void14 {15 dep[u] = dep[pa] + 1;16 fa[u][0] = pa;17 for (int i = 1; i <= 31;i++)18 fa[u][i] = fa[fa[u][i - 1]][i - 1];19 for(int v : adj[u])20 {21 if(v != pa)22 self(self, v, u);23 }24 };25 dep[0] = 0;26 dfs(dfs, s, 0);27 auto lca = [&](int u, int v) -> int28 {29 if(dep[u] < dep[v])30 swap(u, v);31 for (int i = 31; i >= 0;i--)32 {33 if(dep[fa[u][i]] >= dep[v])34 u = fa[u][i];35 }36 if(u == v)37 return v;38 for (int i = 31; i >= 0;i--)39 {40 if(fa[u][i] != fa[v][i])41 {42 u = fa[u][i];43 v = fa[v][i];44 }45 }46 return fa[u][0];47 };48 for (int i = 0; i < m;i++)49 {50 int a, b;51 cin >> a >> b;52 cout << lca(a, b) << "\n";53 }数论,几何,多项式
多项式
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4
5const i64 MOD = 998244353;6const int G = 3;7
8i64 qpow(i64 a, i64 b)9{10 i64 res = 1;11 a = (a % MOD + MOD) % MOD;12 while(b)13 {14 if(b & 1)15 res = res * a % MOD;16 a = a * a % MOD;17 b >>= 1;18 }19 return res;20}21
22namespace NTT23{24 vector<i64> rev;25 void initRev(int limit)26 {27 if(limit <= 1)28 return;29 if(rev.size() == limit)30 return;31 int l = __builtin_ctz(limit);32 rev.resize(limit);33 for (int i = 0; i < limit;i++)34 rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));35 }36
37 void transform(vector<i64> &a, int flag)38 {39 int n = a.size();40
41 initRev(n);42 for(int i = 0;i < n;i++)43 if(i < rev[i])44 swap(a[i], a[rev[i]]);45
46 for (int mid = 1; mid < n;mid <<= 1)47 {48 i64 wn = qpow(G, (MOD - 1) / (mid << 1));49 if(flag == -1)50 wn = qpow(wn, MOD - 2);51
52 for (int i = 0; i < n;i += (mid << 1))53 {54 i64 w = 1;55 for (int j = 0; j < mid;j++, w = w * wn % MOD)56 {57 i64 x = a[i + j];58 i64 y = w * a[i + j + mid] % MOD;59 a[i + j] = (x + y >= MOD ? x + y - MOD : x + y);60 a[i + j + mid] = (x - y < 0 ? x - y + MOD : x - y);61 }62 }63 }64
65 if(flag == -1)66 {67 i64 invN = qpow(n, MOD - 2);68 for (int i = 0; i < n;i++)69 a[i] = a[i] * invN % MOD;70 }71 }72}73
74struct Poly75{76 vector<i64> a;77
78 Poly() {}79 explicit Poly(int size) : a(size, 0) {}80 Poly(const vector<i64> &a_) : a(a_) {}81 Poly(initializer_list<i64> a_) : a(a_) {}82
83 int size() const { return a.size(); }84 void resize(int n) { a.resize(n); }85
86 i64 operator[](int idx) const { return idx < size() ? a[idx] : 0; }87 i64 &operator[](int idx) { return a[idx]; }88
89 Poly modXk(int k) const90 {91 k = min(k, size());92 return Poly(vector<i64>(a.begin(), a.begin() + k));93 }94
95 Poly mulXk(int k) const96 {97 auto b = a;98 b.insert(b.begin(), k, 0);99 return Poly(b);100 }101
102 friend Poly operator+(const Poly &A, const Poly &B)103 {104 Poly res(max(A.size(), B.size()));105 for (int i = 0; i < res.size(); i++)106 res[i] = (A[i] + B[i]) % MOD;107 return res;108 }109
110 friend Poly operator-(const Poly &A, const Poly &B)111 {112 Poly res(max(A.size(), B.size()));113 for (int i = 0; i < res.size(); i++)114 res[i] = (A[i] - B[i] + MOD) % MOD;115 return res;116 }117
118 friend Poly operator*(Poly A, Poly B)119 {120 if(A.size() == 0 || B.size() == 0)121 return Poly();122
123 int n = A.size(), m = B.size();124 int limit = 1;125 while(limit < n + m - 1)126 limit <<= 1;127
128 A.resize(limit);129 B.resize(limit);130 NTT::transform(A.a, 1);131 NTT::transform(B.a, 1);132 for (int i = 0; i < limit;i++)133 A[i] = A[i] * B[i] % MOD;134
135 NTT::transform(A.a, -1);136 A.resize(n + m - 1);137 return A;138 }139
140 friend Poly operator*(Poly A, i64 k)141 {142 k = (k % MOD + MOD) % MOD;143 for (int i = 0; i < A.size();i++)144 A[i] = A[i] * k % MOD;145 return A;146 }147
148 Poly deriv() const149 {150 if(size() <= 1)151 return Poly({0});152 Poly res(size() - 1);153 for (int i = 1;i < size(); i++)154 res[i - 1] = a[i] * i % MOD;155 return res;156 }157
158 Poly integr() const159 {160 Poly res(size() + 1);161 for (int i = 0; i < size();i++)162 res[i + 1] = a[i] * qpow(i + 1, MOD - 2) % MOD;163 return res;164 }165
166 Poly inv(int deg) const167 {168 Poly res({qpow(a[0], MOD - 2)});169 int k = 1;170 while(k < deg)171 {172 k <<= 1;173 Poly cur = modXk(k);174 res = (res * (Poly({2}) - cur * res)).modXk(k);175 }176 return res.modXk(deg);177 }178
179 Poly ln(int deg) const180 {181 return (deriv() * inv(deg)).integr().modXk(deg);182 }183
184 Poly exp(int deg) const185 {186 Poly res({1});187 int k = 1;188 while(k < deg)189 {190 k <<= 1;191 Poly cur = modXk(k);192 res = (res * (Poly({1}) - res.ln(k) + cur)).modXk(k);193 }194 return res.modXk(deg);195 }196};高斯消元
1#include <bits/stdc++.h>2using namespace std;3using db = double;4struct Gauss5{6 static constexpr db EPS = 1e-8;7 //a n * (n + 1)8 static int solve(vector<vector<db>> &a,vector<db> &res)9 {10 int n = a.size();11 int r = 0;// r 记录当前主元要放的行数,也代表矩阵的秩12 for (int i = 0; i < n;i++)13 {14 int maxrow = r;15 for (int j = r + 1; j < n;j++)16 {17 if(abs(a[j][i]) > abs(a[maxrow][i]))18 maxrow = j;19 }20 if(abs(a[maxrow][i]) < EPS)21 continue;// 注意:这里跳过这一列,r 不增加!22 swap(a[r], a[maxrow]);23 db pivot = a[i][i];24 for (int j = i; j <= n;j++)25 a[i][j] /= pivot;26 for (int j = 0; j < n;j++)27 {28 if(i != j)29 {30 db factor = a[j][i];31 for (int k = i; k <= n;k++)32 a[j][k] -= factor * a[i][k];33 }34 }35 r++;36 }37 if(r < n)// 不满秩,说明有自由变量或者矛盾38 {39 for (int i = r; i < n;i++)40 {41 if(abs(a[i][n]) > EPS)42 return -1;// 无解43 }44 return 0;// 0 = 0,无穷多解45 }46 res.resize(n);47 for (int i = 0; i < n;i++)48 res[i] = a[i][n];49 return 1;50 }51};矩阵快速幂
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4const int MOD = 1e9 + 7;5struct Matrix6{7 int n;8 vector<vector<i64>> mat;9 Matrix(int _n) : n(_n)10 {11 mat.assign(n, vector<i64>(n, 0));12 }13 void init()14 {15 for (int i = 0; i < n;i++)16 mat[i][i] = 1;17 }18 Matrix operator*(const Matrix &other) const19 {20 Matrix res(n);21 for (int i = 0; i < n;i++)22 {23 for (int k = 0; k < n;k++)24 {25 i64 r = mat[i][k];26 if(r == 0)27 continue;// 剪枝:如果是 0 就没必要去乘这一整行了28 for (int j = 0; j < n;j++)29 {30 res.mat[i][j] = (res.mat[i][j] + r * other.mat[k][j]) % MOD;31 }32 }33 }34 return res;35 }36 static Matrix qpow(Matrix a, i64 k)37 {38 Matrix res(a.n);39 res.init();40 while(k > 0)41 {42 if(k & 1)43 res = res * a;44 a = a * a;45 k >>= 1;46 }47 return res;48 }49};EXGCD
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4using i128 = __int128;5ostream &operator<<(ostream &os, i128 n) {6 string s;7 if(n == 0)8 s = "0";9 if(n < 0)10 {11 s += "-";12 n = -n;13 }14 while (n) {15 s += '0' + n % 10;16 n /= 10;17 }18 reverse(s.begin(), s.end());19 return os << s;20}21istream &operator>>(istream &is,i128& n)22{23 n = 0;24 string s;25 is >> s;26 for (int i = 0; i < s.size();i++)27 {28 n = n * 10 + s[i] - '0';29 }30 return is;31}32struct exgcd33{34 struct result35 {36 i128 x, y, g;37 bool f;38 };39 //ExGCD 找到通解公式40 // 求解 ax + by = c41 // 返回结构体包含一组特解 x, y,最大公约数 g,以及是否有解42 //对于static来说,可以通过exgcd::使用命名空间直接调用而不用创建实例43 static result solve(i64 a,i64 b,i64 c)44 {45 i128 x = 1, y = 0, g = a;46 function<void(i64, i64)> dfs = [&](i64 a, i64 b)47 {48 if(b == 0)49 {50 g = a;51 x = 1, y = 0;52 return;53 }54 dfs(b, a % b);55 i128 tp = x;56 x = y;//更新x57 y = tp - (i128)(a / b) * y;//更新y58 };59 dfs(a, b);60 if(g < 0)//保证最大公约数为正的61 {62 g = -g;63 x = -x;64 y = -y;65 }66 if(c % g)//如果gcd(a,b)不能整除c,说明无解67 {68 return {0, 0, g, false};69 }70 i128 factor = c / g;71 return {x * factor, y * factor, g, true};72 }73 //获取 x 的最小非负整数解74 //返回 {x_min, g},若无解返回 {-1, -1},这里的g是gcd(a,b)75 //ax + by = c76 static pair<i128,i64> minx(i64 a,i64 b,i64 c)77 {78 result res = solve(a, b, c);79 if(!res.f)80 return {-1, -1}81 if(c == 0)82 return {0, (i64)res.g};83 i128 bg = b / res.g;84 if(bg < 0)85 bg = -bg;86 i128 k = -res.x / bg;87 while(res.x + k * bg < 0)88 k++;89 while(res.x + (k - 1) * bg >= 0)90 k--;91 i128 x = res.x + k * bg;92 return {x, (i64)res.g};93 }94};欧拉筛
1#include <bits/stdc++.h>2using namespace std;3vector<int> primes,isPrime;4void sieve(int n)5{6 isPrime.assign(n + 1, 1);7 isPrime[1] = 0;8 for (int i = 2; i <= n; ++i)9 {10 if (isPrime[i])11 primes.push_back(i);12 for (auto p : primes)13 {14 if(i * p > n)15 break;16 isPrime[i * p] = 0;17 if(i % p == 0)18 break;19 }20 }21}欧拉函数 莫比乌斯函数,因数函数,因数个数函数
1//欧拉函数,表示小于等于 n 且与 n 互质的正整数个数。2#include <bits/stdc++.h>3using namespace std;4
5//求解单个函数的欧拉函数。6int phi(int n)7{8 int res = n;9 for (int i = 2; i * i <= n;i++)10 {11 if(n % i == 0)12 {13 while(n % i == 0)14 n /= i;15 res = res / i * (i - 1);16 }17 }18 if(n > 1)19 res = res / n * (n - 1);20 return res;21}22
23//线性筛同时求欧拉函数和莫比乌斯函数24namespace sieve25{26 int n;27 vector<int> primes;28 vector<int> phi, mu, vis;29
30 void init(int n_)31 {32 n = n_;33 primes.clear();34 phi.assign(n + 1, 0);35 mu.assign(n + 1, 0);36 vis.assign(n + 1, 0);37 }38
39 void run()40 {41 phi[1] = 1;42 mu[1] = 1;43 for (int i = 2; i <= n;i++)44 {45 if(!vis[i]) // 没被访问过,说明是质数46 {47 primes.push_back(i);48 phi[i] = i - 1;49 mu[i] = -1;50 }51
52 for(int p : primes) // 假设已经知道 i,转移到 i * p53 {54 if(1ll * i * p > n)55 break;56
57 int x = i * p;58 vis[x] = 1;59
60 if(i % p == 0)// i本身含有p这个因子61 {62 phi[x] = phi[i] * p;63 mu[x] = 0;64 // 当 p | i 时,说明 p 是当前 i * p 的最小质因子。继续用更大的质数去筛,会破坏“每个合数只被最小质因子筛一次”的性质。65 break;66 }67 else // p是新加入的这个质数因子68 {69 phi[x] = phi[i] * (p - 1);//直接乘上phi[p]70 mu[x] = -mu[i];// 符号翻转71 }72 }73 }74 }75}求逆元
1#include <bits/stdc++.h>2using namespace std;3//exgcd求法4template<class T>5T exgcd(T a,T b,T &x,T &y)6{7 if(b == 0)8 {9 x = 1;10 y = 0;11 return a;12 }13 T d = exgcd(b, a % b, y, x);14 y = y - (a / b) * x;15 return d;16}17//求a在模m下的逆元18template<class T>19T inv1(T a,T m)20{21 T x, y;22 T g = exgcd(a, m, x, y);23 if(g != 1)24 return -1;25 return (x % m + m) % m;26}27//快速幂,仅限模数为质数28template<class T>29T qpow(T a,T b,T MOD)30{31 T res = 1;32 a %= MOD;33 while(b)34 {35 if(b & 1)36 res = res * a % MOD;37 a = a * a % MOD;38 b >>= 1;39 }40 return res % MOD;41}42template <class T>43T inv2(T a,T p)44{45 return qpow(a, p - 2, p);46}47//线性求逆元48vector<int> inv;49void invarr(int n,int p)50{51 inv.assign(n + 5, 0);52 inv[1] = 1;53 for (int i = 2; i <= n;i++)54 inv[i] = 1ll * (p - p / i) * inv[p % i] % p;55}自动取模运算
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4template<class T>5constexpr T qpow(T a,i64 b)6{7 T res = 1;8 while(b)9 {10 if(b & 1)11 res = res * a;12 a = a * a;13 b >>= 1;14 }15 return res;16}17constexpr i64 mul(i64 a, i64 b, i64 p) {18 i64 res = a * b - i64(1.L * a * b / p) * p;19 res %= p;20 if (res < 0) res += p;21 return res;22}23template<i64 P>24struct MLong25{26 i64 x;27 constexpr MLong() : x{} {}28 constexpr MLong(i64 x) : x{norm(x % getMod())} {}29 static i64 Mod;30 constexpr static i64 getMod()31 {32 if(P > 0)33 return P;34 else35 return Mod;36 }37 constexpr static void setMod(i64 Mod_)38 {39 Mod = Mod_;40 }41 constexpr i64 norm(i64 x) const42 {43 if(x < 0)44 x += getMod();45 if(x >= getMod())46 x -= getMod();47 return x;48 }49 constexpr i64 val() const50 {51 return x;52 }53 explicit constexpr operator i64() const54 {55 return x;56 }57 constexpr MLong operator-() const58 {59 MLong res;60 res.x = norm(getMod() - x);61 return res;62 }63 constexpr MLong inv() const64 {65 assert(x != 0);66 return qpow(*this, getMod() - 2);67 }68 constexpr MLong &operator*=(MLong rhs) &69 {70 x = mul(x, rhs.x, getMod());71 return *this;72 }73 constexpr MLong &operator+=(MLong rhs) &74 {75 x = norm(x + rhs.x);76 return *this;77 }78 constexpr MLong &operator-=(MLong rhs) &79 {80 x = norm(x - rhs.x);81 return *this;82 }83 constexpr MLong &operator/=(MLong rhs) &84 {85 return *this *= rhs.inv();86 }87 friend constexpr MLong operator*(MLong lhs, MLong rhs)88 {89 MLong res = lhs;90 res *= rhs;91 return res;92 }93 friend constexpr MLong operator+(MLong lhs, MLong rhs)94 {95 MLong res = lhs;96 res += rhs;97 return res;98 }99 friend constexpr MLong operator-(MLong lhs, MLong rhs)100 {101 MLong res = lhs;102 res -= rhs;103 return res;104 }105 friend constexpr MLong operator/(MLong lhs, MLong rhs)106 {107 MLong res = lhs;108 res /= rhs;109 return res;110 }111 friend constexpr istream &operator>>(istream &is,MLong &a)112 {113 i64 v;114 is >> v;115 a = MLong(v);116 return is;117 }118 friend constexpr ostream &operator<<(ostream &os,MLong &a)119 {120 return os << a.val();121 }122 friend constexpr bool operator==(MLong lhs,MLong rhs)123 {124 return lhs.val == rhs.val();125 }126 friend constexpr bool operator!= (MLong lhs,MLong rhs)127 {128 return lhs.val() != rhs.val();129 }130};131template <>132i64 MLong<0ll>::Mod = (i64)1e18 + 9;133template<int P>134struct MInt135{136 int x;137 constexpr MInt() : x{} {}138 constexpr MInt(i64 x) : x{norm(x % getMod())} {}139 static int Mod;140 constexpr static int getMod()141 {142 if(P > 0)143 return P;144 else145 return Mod;146 }147 constexpr static void setMod(int Mod_)148 {149 Mod = Mod_;150 }151 constexpr int norm(int x) const152 {153 if (x < 0) {154 x += getMod();155 }156 if (x >= getMod()) {157 x -= getMod();158 }159 return x;160 }161 constexpr int val() const162 {163 return x;164 }165 explicit constexpr operator int() const166 {167 return x;168 }169 constexpr MInt operator-() const170 {171 MInt res;172 res.x = norm(getMod() - x);173 return res;174 }175 constexpr MInt inv() const176 {177 assert(x != 0);178 return qpow(*this, getMod() - 2);179 }180 constexpr MInt &operator*=(MInt rhs) &181 {182 x = 1LL * x * rhs.x % getMod();183 return *this;184 }185 constexpr MInt &operator+=(MInt rhs) &186 {187 x = norm(x + rhs.x);188 return *this;189 }190 constexpr MInt &operator-=(MInt rhs) &191 {192 x = norm(x - rhs.x);193 return *this;194 }195 constexpr MInt &operator/=(MInt rhs) &196 {197 return *this *= rhs.inv();198 }199 friend constexpr MInt operator*(MInt lhs, MInt rhs)200 {201 MInt res = lhs;202 res *= rhs;203 return res;204 }205 friend constexpr MInt operator+(MInt lhs, MInt rhs)206 {207 MInt res = lhs;208 res += rhs;209 return res;210 }211 friend constexpr MInt operator-(MInt lhs, MInt rhs)212 {213 MInt res = lhs;214 res -= rhs;215 return res;216 }217 friend constexpr MInt operator/(MInt lhs, MInt rhs)218 {219 MInt res = lhs;220 res /= rhs;221 return res;222 }223 friend constexpr std::istream &operator>>(std::istream &is, MInt &a)224 {225 i64 v;226 is >> v;227 a = MInt(v);228 return is;229 }230 friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a)231 {232 return os << a.val();233 }234 friend constexpr bool operator==(MInt lhs, MInt rhs)235 {236 return lhs.val() == rhs.val();237 }238 friend constexpr bool operator!=(MInt lhs, MInt rhs)239 {240 return lhs.val() != rhs.val();241 }242};243template<>244int MInt<0>::Mod = 998244353;245constexpr int P = 998244353;246using Z = MInt<P>;247int main()248{249 i64 nr;250 cin >> nr;251 Z n = nr;252 Z sum_i = n * (n + 1) / 2;253 Z sum_i2 = n * (n + 1) * (2 * n + 1) / 6;254 Z sum_const = Z(2) * n;255 Z ans = sum_i2 + Z(3) * sum_i + sum_const;256 cout << ans / n;257}组合数
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4template<class T>5constexpr T qpow(T a,i64 b)6{7 T res = 1;8 while(b)9 {10 if(b & 1)11 res = res * a;12 a = a * a;13 b >>= 1;14 }15 return res;16}17constexpr i64 mul(i64 a, i64 b, i64 p) {18 i64 res = a * b - i64(1.L * a * b / p) * p;19 res %= p;20 if (res < 0) res += p;21 return res;22}23struct MLong24{25 i64 x;26 constexpr MLong() : x{} {}27 constexpr MLong(i64 x) : x{norm(x % getMod())} {}28 static i64 Mod;29 constexpr static i64 getMod()30 {31 if(P > 0)32 return P;33 else34 return Mod;35 }36 constexpr static void setMod(i64 Mod_)37 {38 Mod = Mod_;39 }40 constexpr i64 norm(i64 x) const41 {42 if(x < 0)43 x += getMod();44 if(x >= getMod())45 x -= getMod();46 return x;47 }48 constexpr i64 val() const49 {50 return x;51 }52 explicit constexpr operator i64() const53 {54 return x;55 }56 constexpr MLong operator-() const57 {58 MLong res;59 res.x = norm(getMod() - x);60 return res;61 }62 constexpr MLong inv() const63 {64 assert(x != 0);65 return qpow(*this, getMod() - 2);66 }67 constexpr MLong &operator*=(MLong rhs) &68 {69 x = mul(x, rhs.x, getMod());70 return *this;71 }72 constexpr MLong &operator+=(MLong rhs) &73 {74 x = norm(x + rhs.x);75 return *this;76 }77 constexpr MLong &operator-=(MLong rhs) &78 {79 x = norm(x - rhs.x);80 return *this;81 }82 constexpr MLong &operator/=(MLong rhs) &83 {84 return *this *= rhs.inv();85 }86 friend constexpr MLong operator*(MLong lhs, MLong rhs)87 {88 MLong res = lhs;89 res *= rhs;90 return res;91 }92 friend constexpr MLong operator+(MLong lhs, MLong rhs)93 {94 MLong res = lhs;95 res += rhs;96 return res;97 }98 friend constexpr MLong operator-(MLong lhs, MLong rhs)99 {100 MLong res = lhs;101 res -= rhs;102 return res;103 }104 friend constexpr MLong operator/(MLong lhs, MLong rhs)105 {106 MLong res = lhs;107 res /= rhs;108 return res;109 }110 friend constexpr istream &operator>>(istream &is,MLong &a)111 {112 i64 v;113 is >> v;// 1. 先从流中读入一个普通的 long long (v)114 a = MLong(v);// 2. 利用构造函数把 v 包装成 MLong 类型(会自动取模)115 return is;// 3. 把流原样返回116 }117 friend constexpr ostream &operator<<(ostream &os,MLong &a)118 {119 return os << a.val();120 }121 friend constexpr bool operator==(MLong lhs,MLong rhs)122 {123 return lhs.val() == rhs.val();124 }125 friend constexpr bool operator!= (MLong lhs,MLong rhs)126 {127 return lhs.val() != rhs.val();128 }129};130template <>131i64 MLong<0ll>::Mod = (i64)1e18 + 9;132template<int P>133struct MInt134{135 int x;136 constexpr MInt() : x{} {}137 constexpr MInt(i64 x) : x{norm(x % getMod())} {}138
139 static int Mod;140 constexpr static int getMod()141 {142 if(P > 0)143 return P;144 else145 return Mod;146 }147 constexpr static void setMod(int Mod_)148 {149 Mod = Mod_;150 }151 constexpr int norm(int x) const152 {153 if (x < 0) {154 x += getMod();155 }156 if (x >= getMod()) {157 x -= getMod();158 }159 return x;160 }161 constexpr int val() const162 {163 return x;164 }165 explicit constexpr operator int() const166 {167 return x;168 }169 constexpr MInt operator-() const170 {171 MInt res;172 res.x = norm(getMod() - x);173 return res;174 }175 constexpr MInt inv() const176 {177 assert(x != 0);178 return qpow(*this, getMod() - 2);179 }180 constexpr MInt &operator*=(MInt rhs) &181 {182 x = 1LL * x * rhs.x % getMod();183 return *this;184 }185 constexpr MInt &operator+=(MInt rhs) &186 {187 x = norm(x + rhs.x);188 return *this;189 }190 constexpr MInt &operator-=(MInt rhs) &191 {192 x = norm(x - rhs.x);193 return *this;194 }195 constexpr MInt &operator/=(MInt rhs) &196 {197 return *this *= rhs.inv();198 }199 friend constexpr MInt operator*(MInt lhs, MInt rhs)200 {201 MInt res = lhs;202 res *= rhs;203 return res;204 }205 friend constexpr MInt operator+(MInt lhs, MInt rhs)206 {207 MInt res = lhs;208 res += rhs;209 return res;210 }211 friend constexpr MInt operator-(MInt lhs, MInt rhs)212 {213 MInt res = lhs;214 res -= rhs;215 return res;216 }217 friend constexpr MInt operator/(MInt lhs, MInt rhs)218 {219 MInt res = lhs;220 res /= rhs;221 return res;222 }223 friend constexpr std::istream &operator>>(std::istream &is, MInt &a)224 {225 i64 v;226 is >> v;227 a = MInt(v);228 return is;229 }230 friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a)231 {232 return os << a.val();233 }234 friend constexpr bool operator==(MInt lhs, MInt rhs)235 {236 return lhs.val() == rhs.val();237 }238 friend constexpr bool operator!=(MInt lhs, MInt rhs)239 {240 return lhs.val() != rhs.val();241 }242};243template<>244int MInt<0>::Mod = 998244353;245template<int V, int P>246constexpr MInt<P> CInv = MInt<P>(V).inv();247constexpr int P = 998244353;248using Z = MInt<P>;249struct Comb250{251 int n;252 vector<Z> _fac;//存储阶乘(Factorial)253 vector<Z> _invfac;//存储阶乘的逆元(Inverse Factorial)254 vector<Z> _inv;//存储单个数字的逆元(Inverse)255 Comb() : n{0}, _fac{1}, _invfac{1},_inv{0} {}256 Comb(int n) : Comb()257 {258 init(n);259 }260 void init(int m)261 {262 m = min(m, Z::getMod() - 1);263 if(m <= n)264 return;265 _fac.resize(m + 1);266 _invfac.resize(m + 1);267 _inv.resize(m + 1);268
269 for (int i = n + 1; i <= m;i++)270 {271 _fac[i] = _fac[i - 1] * i;272 }273 _invfac[m] = _fac[m].inv();// 唯一一次快速幂先算出最大数 m 的逆元。然后倒着推274 for (int i = m; i > n;i--)275 {276 _invfac[i - 1] = _invfac[i] * i;277 _inv[i] = _invfac[i] * _fac[i - 1];278 }279 n = m;280 }281 Z fac(int m)282 {283 if(m > n)284 init(2 * m);285 return _fac[m];286 }287 Z invfac(int m)288 {289 if(m > n)290 init(2 * m);291 return _invfac[m];292 }293 Z inv(int m)294 {295 if(m > n)296 init(2 * m);297 return _inv[m];298 }299 Z binom(int n,int m)300 {301 if(n < m || m < 0)302 return 0;303 return fac(n) * invfac(m) * invfac(n - m);304 }305};图论
二分图最大匹配(基于 Dinic)
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4
5constexpr i64 MOD = 998244353, INF = 1e9;6
7struct Dinic8{9 struct Edge10 {11 int to;12 int cap;13 int flow;14 int rev;15 };16
17 int n;18 vector<vector<Edge>> adj;19 vector<int> level;20 vector<int> ptr;21
22 Dinic(int n_)23 {24 init(n_);25 }26
27 void init(int n_)28 {29 n = n_;30 adj.assign(n + 1, vector<Edge>());31 level.resize(n + 1);32 ptr.resize(n + 1);33 }34
35 void addEdge(int from, int to , int cap)36 {37 adj[from].push_back({to, cap, 0, (int)adj[to].size()});38 adj[to].push_back({from, 0, 0, (int)adj[from].size() - 1});39 }40
41 bool bfs(int s, int t)42 {43 fill(level.begin(), level.end(), -1);44 level[s] = 0;45 queue<int> q;46 q.push(s);47
48 while(!q.empty())49 {50 int u = q.front();51 q.pop();52
53 for(auto &[to, cap, flow, rev] : adj[u])54 {55 if(cap - flow > 0 && level[to] == -1)56 {57 level[to] = level[u] + 1;58 q.push(to);59 }60 }61 }62
63 return level[t] != -1;64 }65
66 int dfs(int v, int t, int pushed)67 {68 if(pushed == 0)69 return 0;70 if(v == t)71 return pushed;72
73 for (int &cid = ptr[v]; cid < adj[v].size(); cid++)74 {75 auto &[to, cap, flow, rev] = adj[v][cid];76 int tr = to;77
78 if(level[v] + 1 != level[tr] || cap - flow == 0)79 continue;80
81 int push = dfs(tr, t, min(pushed, cap - flow));82 if(push == 0)83 continue;84
85 flow += push;86 adj[tr][rev].flow -= push;87 return push;88 }89 return 0;90 }91
92 int maxFlow(int s, int t)93 {94 int flow = 0;95 while(bfs(s, t))96 {97 fill(ptr.begin(), ptr.end(), 0);98
99 while(int pushed = dfs(s, t, INF))100 flow += pushed;101 }102 return flow;103 }104};105
106void solve()107{108 int n, m, e;109 cin >> n >> m >> e;110
111 int s = 0;// 超级源点 S 的身份证号112 int t = n + m + 1;// 超级汇点 T 的身份证号113 Dinic dinic(t);// 告诉 Dinic 引擎,图中最大的编号是 t114
115 // 1. 超级源点 S 连接所有左部点,容量为 1116 for (int i = 1; i <= n;i++)117 {118 dinic.addEdge(s, i, 1);119 }120
121 // 2. 所有右部点连接超级汇点 T,容量为 1122 for (int i = 1; i <= m;i++)123 {124 dinic.addEdge(n + i, t, 1);125 }126
127 // 3. 读取边,连接左右部点128 for (int i = 0; i < e;i++)129 {130 int u, v;131 cin >> u >> v;132 // 左部点 u,右部点 v (为了避免编号冲突,右部点编号加上 n)133 // 即使有重边也没关系,最大流算法会自动处理134 dinic.addEdge(u, n + v, 1);135 }136
137 // 输出最大匹配数(即最大流)138 cout << dinic.maxFlow(s, t) << "\n";139}140
141signed main()142{143 ios::sync_with_stdio(0);144 cin.tie(0);145 int T = 1;146 // cin >> T;147 while(T--)148 solve();149
150 return 0;151}割点 与 点双连通分量 (v-BCC)
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4
5struct VBCC6{7 int n;8 vector<vector<int>> adj;9 vector<int> dfn, low, isCut, stk;10 int dfncnt, vbccnt, cutcnt;11 vector<vector<int>> vbc;12
13 VBCC(int n_)14 {15 init(n_);16 }17
18 void init(int n_)19 {20 n = n_;21 adj.assign(n + 1, vector<int>());22 dfn.assign(n + 1, 0);23 low.resize(n + 1);24 isCut.assign(n + 1, 0);25 stk.clear();26 vbc.clear();27 dfncnt = vbccnt = cutcnt = 0;28 }29
30 void addEdge(int u, int v)31 {32 adj[u].push_back(v);33 adj[v].push_back(u);34 }35
36 void dfs(int u, int p = 0)37 {38 dfn[u] = low[u] = ++dfncnt;39 stk.push_back(u);40 int child = 0;41
42 if(p == 0 && adj[u].empty())43 {44 vbccnt++;45 stk.pop_back();46 vbc.push_back({u});47 return;48 }49
50 for(int v : adj[u])51 {52 if(!dfn[v])53 {54 child++;55 dfs(v, u);56 low[u] = min(low[u], low[v]);57
58 if(low[v] >= dfn[u])59 {60 isCut[u] = 1;61 vbccnt++;62 vector<int> comp;63 while(1)64 {65 int x = stk.back();66 stk.pop_back();67 comp.push_back(x);68 if(x == v)69 break;70 }71 comp.push_back(u);72 vbc.push_back(comp);73 }74 }75 else if(v != p)76 {77 low[u] = min(low[u], dfn[v]);78 }79 }80 if(p == 0 && child < 2)81 isCut[u] = 0;82 }83
84 void work()85 {86 for (int i = 1; i <= n;i++)87 {88 if(!dfn[i])89 {90 stk.clear();91 dfs(i);92 }93 }94 for (int i = 1; i <= n;i++)95 {96 if(isCut[i])97 cutcnt++;98 }99 }100};割边 (桥) 与 边双连通分量 (e-BCC)
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4typedef pair<int, int> pii;5struct EBCC6{7 int n;8 vector<vector<pii>> adj;9 vector<int> dfn, low, stk;10 int dfncnt, ebccnt, bridgecnt;11 vector<vector<int>> ebc;12 EBCC(int n_)13 {14 init(n_);15 }16
17 void init(int n_)18 {19 n = n_;20 adj.assign(n + 1, vector<pii>());21 dfn.assign(n + 1, 0);22 low.resize(n + 1, 0);23 stk.clear();24 ebc.clear();25 dfncnt = ebccnt = bridgecnt = 0;26 }27
28 void addEdge(int u, int v, int id)29 {30 adj[u].push_back({v, id});31 adj[v].push_back({u, id});32 }33
34 void dfs(int u, int inEdge = 0)35 {36 dfn[u] = low[u] = ++dfncnt;37 stk.push_back(u);38
39 for(auto &[v, id] : adj[u])40 {41 if(!dfn[v])42 {43 dfs(v, id);44 low[u] = min(low[u], low[v]);45
46 if(low[v] > dfn[u])47 bridgecnt++;48 }49 else if(id != inEdge)50 {51 low[u] = min(low[u], dfn[v]);52 }53 }54
55 if(low[u] == dfn[u])56 {57 ebccnt++;58 vector<int> comp;59 while(1)60 {61 int x = stk.back();62 stk.pop_back();63 comp.push_back(x);64 if(x == u)65 break;66 }67 ebc.push_back(comp);68 }69 }70
71 void work()72 {73 for (int i = 1; i <= n;i++)74 {75 if(!dfn[i])76 {77 stk.clear();78 dfs(i);79 }80 }81 }82};最小费用最大流
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4typedef pair<i64, i64> pll;5const i64 INF = 2e18;6
7struct MCFGraph8{9 struct Edge10 {11 int to;12 i64 cap;13 i64 flow;14 i64 cost;15 int rev;16 };17
18 int n;19 vector<vector<Edge>> adj;20 vector<i64> h;21 vector<i64> dist;22 vector<int> prevV;23 vector<int> prevE;24
25 MCFGraph() {}26 MCFGraph(int n_)27 {28 init(n_);29 }30
31 void init(int n_)32 {33 n = n_;34 adj.assign(n + 1, vector<Edge>());35 h.assign(n + 1, 0);36 dist.resize(n + 1, 0);37 prevV.resize(n + 1);38 prevE.resize(n + 1);39 }40
41 void addEdge(int from, int to, i64 cap, i64 cost)42 {43 adj[from].push_back({to, cap, 0, cost, (int)adj[to].size()});44 adj[to].push_back({from, 0, 0, -cost, (int)adj[from].size() - 1});45 }46
47 pll work(int s, int t)48 {49 i64 maxFlow = 0;50 i64 minCost = 0;51
52 while(1)53 {54 priority_queue<pll, vector<pll>, greater<pll>> pq;55
56 fill(dist.begin(), dist.end(), INF);57 dist[s] = 0;58 pq.push({0, s});59
60 while(!pq.empty())61 {62 auto [d, u] = pq.top();63 pq.pop();64
65 if(dist[u] < d)66 continue;67
68 for (int i = 0; i < adj[u].size(); i++)69 {70 auto &[to, cap, flow, cost, rev] = adj[u][i];71 if(cap - flow > 0)72 {73 i64 reducedCost = cost + h[u] - h[to];74
75 if(dist[to] > dist[u] + reducedCost)76 {77 dist[to] = dist[u] + reducedCost;78 prevV[to] = u;79 prevE[to] = i;80 pq.push({dist[to], to});81 }82 }83 }84 }85
86 if(dist[t] == INF)87 break;88
89 for (int i = 0; i <= n; i++)90 {91 if(dist[i] != INF)92 h[i] += dist[i];93 }94
95 i64 push = 2e18;96 for (int v = t; v != s; v = prevV[v])97 {98 int u = prevV[v];99 int idx = prevE[v];100 push = min(push, adj[u][idx].cap - adj[u][idx].flow);101 }102
103 maxFlow += push;104 minCost += push * h[t];105
106 for (int v = t; v != s; v= prevV[v])107 {108 int u = prevV[v];109 int idx = prevE[v];110 int rev = adj[u][idx].rev;111
112 adj[u][idx].flow += push;113 adj[v][rev].flow -= push;114 }115 }116 return {maxFlow, minCost};117 }118};Dinic 求最大流
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4
5const i64 INF = 2e18;6
7struct Dinic8{9 struct Edge10 {11 int to;12 i64 cap;13 i64 flow;14 int rev;15 };16
17 int n;18 vector<vector<Edge>> adj;19 vector<int> level;20 vector<int> ptr;21
22 Dinic () {}23 Dinic(int n_)24 {25 init(n_);26 }27
28 void init(int n_)29 {30 n = n_;31 adj.assign(n + 1, vector<Edge>());32 level.resize(n + 1);33 ptr.resize(n + 1);34 }35
36 void addEdge(int from, int to , i64 cap)37 {38 adj[from].push_back({to, cap, 0, (int)adj[to].size()});39 adj[to].push_back({from, 0, 0, (int)adj[from].size() - 1});40 }41
42 bool bfs(int s, int t)43 {44 fill(level.begin(), level.end(), -1);45 level[s] = 0;46 queue<int> q;47 q.push(s);48
49 while(!q.empty())50 {51 int u = q.front();52 q.pop();53
54 for(auto &[to, cap, flow, rev] : adj[u])55 {56 if(cap - flow > 0 && level[to] == -1)57 {58 level[to] = level[u] + 1;59 q.push(to);60 }61 }62 }63
64 return level[t] != -1;65 }66
67 i64 dfs(int v, int t, i64 pushed)68 {69 if(pushed == 0)70 return 0;71 if(v == t)72 return pushed;73
74 for (int &cid = ptr[v]; cid < adj[v].size(); cid++)75 {76 auto &[to, cap, flow, rev] = adj[v][cid];77 int tr = to;78
79 if(level[v] + 1 != level[tr] || cap - flow == 0)80 continue;81
82 i64 push = dfs(tr, t, min(pushed, cap - flow));83 if(push == 0)84 continue;85
86 flow += push;87 adj[tr][rev].flow -= push;88 return push;89 }90 return 0;91 }92
93 i64 maxFlow(int s, int t)94 {95 i64 flow = 0;96 while(bfs(s, t))97 {98 fill(ptr.begin(), ptr.end(), 0);99
100 while(i64 pushed = dfs(s, t, INF))101 flow += pushed;102 }103 return flow;104 }105};Prufer序
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4typedef pair<int, int> pii;5struct Prufer6{7 static vector<int> treeToPrufer(int n, const vector<pii> &edges)8 {9 vector<int> pruferSeq;10 if(n <= 2)11 return pruferSeq;12
13 vector<int> degree(n + 1, 0);14 vector<int> xorSum(n + 1, 0);15
16 for(const auto &[u, v] : edges)17 {18 degree[u]++;19 degree[v]++;20 xorSum[u] ^= v;21 xorSum[v] ^= u;22 }23
24 int ptr = 1;25 while(ptr <= n && degree[ptr] != 1)26 ptr++;27
28 int leaf = ptr;29
30 for (int i = 0; i < n - 2;i++)31 {32 int neighbor = xorSum[leaf];33 pruferSeq.push_back(neighbor);34
35 degree[leaf]--;36 degree[neighbor]--;37 xorSum[neighbor] ^= leaf;38
39 if(degree[neighbor] == 1 && neighbor < ptr)40 leaf = neighbor;41 else42 {43 ptr++;44 while(ptr <= n && degree[ptr] != 1)45 ptr++;46 leaf = ptr;47 }48 }49 return pruferSeq;50 }51
52 static vector<pii> pruferToTree(int n, const vector<int> &pruferSeq)53 {54 vector<pii> edges;55 if(n == 2)56 {57 edges.push_back({1, 2});58 return edges;59 }60
61 vector<int> degree(n + 1, 1);62 for(int node : pruferSeq)63 degree[node]++;64
65 int ptr = 1;66 while(ptr <= n && degree[ptr] != 1)67 ptr++;68
69 int leaf = ptr;70 for(int node : pruferSeq)71 {72 edges.push_back({leaf, node});73 degree[leaf]--;74 degree[node]--;75
76 if(degree[node] == 1 && node < ptr)77 leaf = node;78 else79 {80 ptr++;81 while(ptr <= n && degree[ptr] != 1)82 ptr++;83 leaf = ptr;84 }85 }86
87 int u = -1, v = -1;88 for (int i = 1; i <= n;i++)89 {90 if(degree[i] == 1)91 {92 if(u == -1)93 u = i;94 else95 v = i;96 }97 }98
99 if(u != -1 && v != -1)100 edges.push_back({u, v});101
102 return edges;103 }104};强分量缩点
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long4//dfn (DFS Number):时间戳数组。记录每个节点在 DFS 遍历时第一次被访问到的顺序(第几个被发现的)。5// low (Lowest value):追溯值数组。记录当前节点通过它的邻居(包括后代),能够“绕”回到的最早的时间戳(你能回到的最早祖先是谁)。6//bel (Belong):归属数组。这就是缩点后的结果!它记录了原图中的每个点,最终被打包到了哪一个“强连通分量(大胖点)”里。相当于它们在新图里的“新身份证号”。7//stk (Stack栈):用来保存在当前搜索路径上,且还没有被确立归属的节点。8//cur:时间戳发号器(从 0 开始递增)。9//cnt:强连通分量的计数器(最终 cnt 的值就是缩点后新图的节点总数)。10struct SCC11{12 int n;13 vector<vector<int >> adj;14 vector<int> stk;15 vector<int> dfn, low, bel;16 int cur, cnt;17 SCC() {}18 SCC(int n_)19 {20 init(n_);21 }22 //0 -index23 void init(int n_)24 {25 n = n_;26 adj.assign(n, {});27 dfn.assign(n, -1);28 low.resize(n);29 bel.assign(n, -1);30 stk.clear();31 cur = cnt = 0;32 }33 //u -> v34 void addEdge(int u, int v)35 {36 adj[u].push_back(v);37 }38 void dfs(int x)39 {40 dfn[x] = low[x] = cur++;// 一进门,先领个时间戳,并且一开始能回溯到的最早时间就是自己41 stk.push_back(x);// 进栈,表示正在处理中,还没归属42 for(auto y : adj[x])43 {44 if(dfn[y] == -1)//// 如果邻居 y 还没被访问过45 {46 dfs(y);//往下搜47 // 等 y 搜完回来了,用 y 能到达的最早时间来更新 x,因为此时y已经完整跑完了dfs48 low[x] = min(low[x], low[y]);49 }50 else if(bel[y] == -1)51 {52 low[x] = min(low[x], dfn[y]);//我们用y的时间戳更新low[x],因为x可以往回到达y53 }54 }55 if(dfn[x] == low[x])56 {57 int y;58 do{59 y = stk.back();// 把栈里在自己之上的兄弟全弹出来60 bel[y] = cnt;// 给他们统一下发同一个新的身份证号 cnt61 stk.pop_back();62 } while (y != x);// 直到把自己也弹出来为止63 cnt++;// 编号用完了,下一个环用新编号64 }65 }66 vector<int> work()67 {68 for (int i = 0;i < n;i++)69 {70 if(dfn[i] == -1)71 dfs(i);72 }73 return bel;74 }75};树哈希
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4using u64 = unsigned long long;5mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());6
7const u64 MASK = rnd();8
9struct TreeHasher10{11 static u64 shift(u64 x)12 {13 x ^= MASK;14 x ^= x << 13;15 x ^= x >> 7;16 x ^= x << 17;17 x ^= MASK;18 return x;19 }20};最小生成树Prim
1#include <bits/stdc++.h>2using namespace std;3const int MAXN = 5e3 + 5;4const int MAXM = 2e5 + 5;5const int INF = 1e9;6struct edge {7 int v;// 这条边的终点去哪? (Destination)8 int w;// 这条边有多长? (Weight)9 int next = 0;// 同一个起点的“上一条边”在哪? (Linked List)10} e[MAXM << 1];// 无向图,边数要开 2 倍11
12int head[MAXN];// head[u] 表示:以 u 为起点的“最后加入的那条边”在数组 e 中的下标。13int cnt;// 给边编号的计数器。14int dis[MAXN];// 它代表 点 i 距离“最小生成树”这个集合的最短距离。15int vis[MAXN];// 标记数组:vis[i]=true 表示点 i 已经在生成树中16int n, m, tot, ans;// tot记录已加入生成树的点数17inline void add(int u,int v,int w)18{19 e[++cnt].v = v;// 1. 申请一个新的边位置 cnt,记录终点是 v20 e[cnt].w = w;// 2. 记录权值是 w21 // 下面这两步是“插头法”链接:22 e[cnt].next = head[u];// 3. 新边的 next 指向 u 节点原本的第一条边23 head[u] = cnt;// 4. 更新 u 节点的第一条边为当前这条新边24}25inline int prim()26{27 for (int i = 2; i <= n;i++)28 {29 dis[i] = INF;30 }31 for (int i = head[1]; i;i = e[i].next)32 {33 dis[e[i].v] = min(dis[e[i].v], e[i].w);34 }35 int now = 1;// now 表示最新加入树的那个点36 vis[1] = 1;// 1号点已入伙37 tot = 1;// 目前树里有 1 个点38 while(tot < n)39 {40 int minn = INF;41 now = 0;42 for (int i = 2; i <= n;i++)43 {44 if(!vis[i] && dis[i] < minn)45 {46 minn = dis[i];// 更新最小距离47 now = i;// 记下这个点48 }49 }50 if(minn == INF)51 {52 cout << "orz";53 return -1;54 }55 ans += minn;56 vis[now] = 1;57 tot++;58 for (int i = head[now]; i;i = e[i].next)59 {60 int v = e[i].v;61 if (!vis[v] &&e[i].w < dis[v])62 {63 dis[v] = e[i].w;64 }65 }66 }67 cout << ans;68 return 0;69}70int main()71{72 ios::sync_with_stdio(0);73 cin.tie(0);74
75 cin >> n >> m;76 int u, v, w;77 for (int i = 0; i < m; i++)78 {79 cin >> u >> v >> w;80 add(u, v, w);81 add(v, u, w);82 }83 prim();84}最小生成树Kruscal
1#include <bits/stdc++.h>2using namespace std;3const int MAXN = 5e3 + 5;4const int MAXM = 2e5 + 5;5struct edge{6 int u;7 int v;8 int w;9} e[MAXM];10struct DSU11{12 vector<int> f, siz;13 DSU() {};14 DSU(int n)15 {16 init(n);17 }18 //input n,open n + 119 void init(int n)20 {21 f.resize(n + 1);22 iota(f.begin(), f.end(), 0);23 siz.assign(n + 1, 1);24 }25 int find(int x)26 {27 while(x != f[x])28 x = f[x] = f[f[x]];29 return x;30 }31 bool same(int x,int y)32 {33 return find(x) == find(y);34 }35 bool merge(int x,int y)36 {37 x = find(x);38 y = find(y);39 if(x == y)40 return false;41 if(siz[x] < siz[y])42 swap(x, y);43 siz[x] += siz[y];44 f[y] = x;45 return true;46 }47 int size(int x)48 {49 return siz[find(x)];50 }51};52int n, m, ans, cnt;53inline bool cmp(edge e1,edge e2)54{55 return e1.w < e2.w;56}57inline void kruskal()58{59 cin >> n >> m;60 DSU ds(n);61 for (int i = 0; i < m; i++)62 {63 cin >> e[i].u >> e[i].v >> e[i].w;64 }65 sort(e, e + m, cmp);66 for (int i = 0; i < m;i++)67 {68 int eu = ds.find(e[i].u);// 找 u 的祖先69 int ev = ds.find(e[i].v);// 找 v 的祖先70 if(eu == ev)71 continue;// 已经在同一个连通块,跳过,防止成环72 ans += e[i].w;// 累加边权73 ds.merge(eu, ev); // 合并两个集合74 if(++cnt == n - 1)75 break;76 }77}78int main()79{80 ios::sync_with_stdio(0);81 cin.tie(0);82 kruskal();83 if(cnt == n - 1)84 {85 cout << ans;86 }87 else88 {89 cout << "orz";90 }91}字符串
字典树Trie
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long4struct Trie5{6 // ch 存储每个节点的子节点编号,这里包含大小写字母加上数字7 vector<array<int, 70>> ch;8 // cnt 记录以当前节点为【结尾】的单词数量9 vector<int> cnt;10 // pre 记录经过当前节点的单词数量(即以此为【前缀】的数量)11 vector<int> pre;12 Trie()13 {14 newNode();// 编号为 0 的节点作为根节点15 }16 int newNode()17 {18 ch.push_back({0});// 初始化所有个子节点均为 019 cnt.push_back(0);20 pre.push_back(0);21 return ch.size() - 1;22 }23 int getId(char c) const24 {25 if(c >= 'a' && c <= 'z')26 return c - 'a';27 else if(c >= 'A' && c <= 'Z')28 return c - 'A' + 26;29 else if(c >= '0' && c <= '9')30 return c - '0' + 52;31 }32 void insert(const string& s)33 {34 int p = 0;// 从根节点开始35 for(char c : s)36 {37 int u = getId(c);//字符映射38 if(!ch[p][u])39 ch[p][u] = newNode();// 如果没有该子节点,则新建40 p = ch[p][u];41 pre[p]++;42 }43 cnt[p]++;//在完整走完之后,此时单词已经抵达终点,终点的计数器+1,表明这里是一个完整单词的结尾44 }45 int search(const string &s)46 {47 int p = 0;48 for(char c : s)49 {50 int u = getId(c);51 if(!ch[p][u])52 return 0;// 匹配中断,说明不存在53 p = ch[p][u];54 }55 return cnt[p];56 }57 int searchPrefix(const string &s)58 {59 int p = 0;60 for(char c : s)61 {62 int u = getId(c);63 if(!ch[p][u])64 return 0;65 p = ch[p][u];66 }67 return pre[p];68 }69};EXKMP
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4//EXKMP用来求“最长公共前缀(LCP)5struct EXKMP6{7 //z[i] 的意思是:把字符串 b 从第 i 个位置开始往后切,切下来的这半截,和原字符串 b 的开头,能有多长是一模一样的?8 vector<int> z;9 //p[i] 的意思是:把字符串 a 从第 i 个位置开始往后切,切下来的这半截,和原字符串 b 的开头,能有多长是一模一样的?10 vector<int> p;11 void get_z(const string& b)12 {13 int m = b.size();14 z.assign(m, 0);15 if(m == 0)// 容错处理,空串直接溜16 return;17 z[0] = m;18 for (int i = 1, l = 0, r = -1; i < m;i++)19 {20 if(i <= r && z[i - l] < r - i + 1)21 z[i] = z[i - l];22 else23 {24 z[i] = max(0, r - i + 1);25 while(i + z[i] < m && b[z[i]] == b[i + z[i]])26 z[i]++;27 }28 if(i + z[i] - 1 > r)// 这其实就是 i + z[i] - 1 > r 的变形29 {30 l = i;31 r = i + z[i] - 1;// r 被推到了新的最远端32 }33 }34 }35 void get_p(const string& a, const string& b)36 {37 int n = a.size(), m = b.size();38 p.assign(n, 0);39 for (int i = 0, l = 0, r = -1; i < n;i++)40 {41 if(i <= r && z[i - l] < r - i + 1)42 p[i] = z[i - l];43 else44 {45 p[i] = max(0, r - i + 1);46 while(i + p[i] < n && p[i] < m && a[i + p[i]] == b[p[i]])47 p[i]++;48
49 }50 if(i + p[i] - 1 > r)51 {52 l = i;53 r = i + p[i] - 1;54 }55 }56 }57};KMP
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4//定义一个字符串 s 的 border 为 s 的一个非 s 本身的子串 t,满足 t 既是 s 的前缀,又是 s 的后缀。5struct KMP6{7 vector<int> pi;// pi[i] 记录长度为 i+1 的前缀的最长 border 长度8 // 1. 预处理模式串 p,构造 pi 数组 (也就是 next 数组)9 void build(const string& p)10 {11 int m = p.size();12 pi.assign(m, 0);// pi[0] 显然是 0,因为真子串不能是原串本身13 for (int i = 1, j = 0; i < m;i++)14 {15 while(j > 0 && p[i] != p[j])16 j = pi[j - 1];17 if(p[i] == p[j])18 j++;19 pi[i] = j;20 }21 }22 vector<int> match(const string& s, const string& p)23 {24 int n = s.size();25 int m = p.size();26 vector<int> res;27 for (int i = 0, j = 0; i < n;i++)28 {29 while(j > 0 && s[i] != p[j])30 j = pi[j - 1];31 if(s[i] == p[j])32 j++;33 if(j == m)34 {35 res.push_back(i - m + 2);36 j = pi[j - 1];37 }38 }39 return res;40 }41};动态规划
数位dp
1#include<iostream>2#include<vector>3us4int a, b;5int pow10[15];6int change(vector<int>num, int l, int r) {7 int ans = 0;8 for (int i = l; i >= r; --i) {9 ans = ans * 10 + num[i];10 }11 return ans;12}13int cal(int n, int x) {14 vector<int>num;15 while (n) {16 num.push_back(n % 10);17 n /= 10;18 }19 n = num.size();20 int res = 0;21 for (int i = n - 1; i >= 0; --i) {22 if ((!x) && (i == n - 1))continue;23 if (i < n - 1) {24 int tem = change(num, n - 1, i + 1);25 if (!x)tem--;26 res += tem * pow10[i];27 }28 if (num[i] == x)res += change(num, i - 1, 0) + 1;29 else if (num[i] > x)res += pow10[i];30 }31 return res;32}33int main() {34 pow10[0] = 1;35 for (int i = 1; i <= 10; ++i) {36 pow10[i] = pow10[i - 1] * 10;37 }38 while (1) {39 cin >> a >> b;40 if (!a && !b)break;41 if (a > b)swap(a, b);42 for (int i = 0; i < 10; ++i) {43 cout << cal(b, i) - cal(a - 1, i) << " ";44 }45 cout << endl;46 }47 return 0;48}杂项
高精度无符号
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4struct BigInt5{6 vector<int> vec;7 BigInt(i64 x = 0)8 {9 if(x == 0)10 vec.push_back(0);11 while(x)12 {13 vec.push_back(x % 10);14 x /= 10;15 }16 }17 BigInt(string s)18 {19 for (int i = s.size() - 1; i >= 0;i--)20 {21 vec.push_back(s[i] - '0');22 }23 trim();24 }25 void trim()26 {27 while(vec.size() > 1 && vec.back() == 0)28 vec.pop_back();29 }30 bool operator<(const BigInt& b) const31 {32 if(vec.size() != b.vec.size())33 return vec.size() < b.vec.size();34 for (int i = vec.size() - 1; i >= 0;i--)35 {36 if(vec[i] != b.vec[i])37 return vec[i] < b.vec[i];38 }39 return false;40 }41 bool operator>(const BigInt &b) const { return b < *this; }42 bool operator<=(const BigInt &b) const { return !(*this > b); }43 bool operator>=(const BigInt &b) const { return !(*this < b); }44 bool operator==(const BigInt &b) const { return vec == b.vec; }45 bool operator!=(const BigInt &b) const { return vec != b.vec; }46 BigInt operator+=(const BigInt& b)47 {48 int t = 0;49 for (int i = 0; i < max(vec.size(), b.vec.size()) || t;i++)50 {51 if(i == vec.size())52 vec.push_back(0);53 vec[i] += t + (i < b.vec.size() ? b.vec[i] : 0);54 t = vec[i] / 10;55 vec[i] %= 10;56 }57 trim();58 return *this;59 }60 friend BigInt operator+(BigInt a,const BigInt& b)61 {62 a += b;63 return a;64 }65 //assume this > b66 BigInt operator-=(const BigInt& b)67 {68 int t = 0;69 for (int i = 0; i < b.vec.size() || t;i++)70 {71 vec[i] -= t + (i < b.vec.size() ? b.vec[i] : 0);72 if(vec[i] < 0)73 {74 vec[i] += 10;75 t = 1;76 }77 else78 t = 0;79 }80 trim();81 return *this;82 }83 friend BigInt operator-(BigInt a,const BigInt& b)84 {85 a -= b;86 return a;87 }88 friend BigInt operator*(const BigInt& a,const BigInt& b)89 {90 if((a.vec.size() == 1 && a.vec[0] == 0) || (b.vec.size() == 1 && b.vec[0] == 0))91 return BigInt(0);92 BigInt res(0);93 res.vec.assign(a.vec.size() + b.vec.size() + 5, 0);94 for (int i = 0; i < a.vec.size();i++)95 {96 for (int j = 0; j < b.vec.size();j++)97 {98 res.vec[i + j] += a.vec[i] * b.vec[j];99 res.vec[i + j + 1] += res.vec[i + j] / 10;100 res.vec[i + j] %= 10;101 }102 }103 res.trim();104 return res;105 }106 BigInt operator*(int b) const107 {108 if(b == 0)109 return BigInt(0);110 BigInt res = *this;111 int t = 0;112 for (int i = 0; i < res.vec.size() || t;i++)113 {114 if(i == res.vec.size())115 res.vec.push_back(0);116 i64 cur = 1ll * res.vec[i] * b + t;117 res.vec[i] = cur % 10;118 t = cur / 10;119 }120 res.trim();121 return res;122 }123 BigInt &operator*=(const BigInt b) &124 {125 *this = *this * b;126 return *this;127 }128 //返回{商,余数}129 static pair<BigInt,BigInt> divmod(BigInt a,const BigInt& b)130 {131 if(a < b)132 return {BigInt{0}, a};133 BigInt q(0), r(0);134 q.vec.assign(a.vec.size(), 0);135 for (int i = a.vec.size() - 1; i >= 0;i--)136 {137 r = r * 10 + a.vec[i];138 int cnt = 0;139 while(r >= b)140 {141 r -= b;142 cnt++;143 }144 q.vec[i] = cnt;145 }146 q.trim();147 return {q, r};148 }149 friend BigInt operator/(BigInt& a,BigInt& b)150 {151 return divmod(a, b).first;152 }153 friend BigInt operator%(BigInt& a,BigInt& b)154 {155 return divmod(a, b).second;156 }157 BigInt operator/=(const BigInt& b)158 {159 *this = divmod(*this, b).first;160 return *this;161 }162 BigInt operator%=(const BigInt& b)163 {164 *this = divmod(*this, b).second;165 return *this;166 }167 friend ostream& operator<<(ostream& os,const BigInt& a)168 {169 for (int i = a.vec.size() - 1; i >= 0;i--)170 os << a.vec[i];171 return os;172 }173 friend istream& operator>>(istream& is,BigInt& a)174 {175 string s;176 if(!(is >> s))177 return is;178 a = BigInt(s);179 return is;180 }181};高精度有符号
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4struct BigInt5{6 vector<int> vec;7 int sign;8 BigInt(i64 x = 0)9 {10 if(x < 0)11 sign = -1, x = -x;12 else13 sign = 1;14 if(x == 0)15 vec.push_back(0);16 while(x)17 {18 vec.push_back(x % 10);19 x /= 10;20 }21 }22 BigInt(string s)23 {24 if(s.empty())25 {26 sign = 1;27 vec = {0};28 return;29 }30 if(s[0] == '-')31 {32 sign = -1;33 s = s.substr(1);34 }35 else36 sign = 1;37 for (int i = s.size() - 1; i >= 0;i--)38 {39 vec.push_back(s[i] - '0');40 }41 trim();42 }43 void trim()44 {45 while(vec.size() > 1 && vec.back() == 0)46 vec.pop_back();47 if(vec.size() == 1 && vec[0] == 0)48 sign = 1;49 }50 static bool abs_less(const BigInt& a,const BigInt &b)51 {52 if(a.vec.size() != b.vec.size())53 return a.vec.size() < b.vec.size();54 for (int i = a.vec.size() - 1; i >= 0;i--)55 {56 if(a.vec[i] != b.vec[i])57 return a.vec[i] < b.vec[i];58 }59 return false;60 }61 bool operator<(const BigInt& b) const62 {63 if(sign != b.sign)64 return sign < b.sign;65 if(sign == 1)66 return abs_less(*this, b);67 else68 return abs_less(b, *this);69 }70 bool operator>(const BigInt &b) const { return b < *this; }71 bool operator<=(const BigInt &b) const { return !(*this > b); }72 bool operator>=(const BigInt &b) const { return !(*this < b); }73 bool operator==(const BigInt &b) const { return (sign == b.sign && vec == b.vec); }74 bool operator!=(const BigInt &b) const { return !(*this == b); }75 static BigInt abs_add(const BigInt& a, const BigInt& b) {76 BigInt res;77 res.vec.clear();78 int t = 0;79 for (int i = 0; i < max(a.vec.size(), b.vec.size()) || t; i++) {80 int cur = t + (i < a.vec.size() ? a.vec[i] : 0) + (i < b.vec.size() ? b.vec[i] : 0);81 res.vec.push_back(cur % 10);82 t = cur / 10;83 }84 return res;85 }86 static BigInt abs_sub(const BigInt& a, const BigInt& b) {87 BigInt res = a;88 int t = 0;89 for (int i = 0; i < b.vec.size() || t; i++) {90 res.vec[i] -= t + (i < b.vec.size() ? b.vec[i] : 0);91 if (res.vec[i] < 0) {92 res.vec[i] += 10;93 t = 1;94 } else t = 0;95 }96 res.trim();97 return res;98 }99 friend BigInt operator+(BigInt a, const BigInt& b) {100 if (a.sign == b.sign) {101 BigInt res = abs_add(a, b);102 res.sign = a.sign;103 return res;104 }105 if (abs_less(a, b)) {106 BigInt res = abs_sub(b, a);107 res.sign = b.sign;108 return res;109 } else {110 BigInt res = abs_sub(a, b);111 res.sign = a.sign;112 return res;113 }114 }115 friend BigInt operator-(BigInt a, BigInt b) {116 b.sign *= -1;117 return a + b;118 }119 friend BigInt operator*(const BigInt& a, const BigInt& b) {120 if ((a.vec.size() == 1 && a.vec[0] == 0) || (b.vec.size() == 1 && b.vec[0] == 0))121 return BigInt(0);122 BigInt res;123 res.vec.assign(a.vec.size() + b.vec.size(), 0);124 for (int i = 0; i < a.vec.size(); i++) {125 for (int j = 0; j < b.vec.size(); j++) {126 res.vec[i + j] += a.vec[i] * b.vec[j];127 res.vec[i + j + 1] += res.vec[i + j] / 10;128 res.vec[i + j] %= 10;129 }130 }131 res.sign = a.sign * b.sign;132 res.trim();133 return res;134 }135 BigInt operator-() const {136 BigInt res = *this;137 if (res != BigInt(0)) res.sign *= -1;138 return res;139 }140 BigInt& operator+=(const BigInt& b) { return *this = *this + b; }141 BigInt& operator-=(const BigInt& b) { return *this = *this - b; }142 BigInt& operator*=(const BigInt& b) { return *this = *this * b; }143 // 核心:绝对值除法 (返回 {绝对值商, 绝对值余数})144 static pair<BigInt, BigInt> abs_divmod(const BigInt& a, const BigInt& b) {145 if (b == BigInt(0)) return {BigInt(0), BigInt(0)}; // 实际应用中应抛出除0异常146 if (abs_less(a, b)) return {BigInt(0), a};147 BigInt q, r(0);148 q.vec.assign(a.vec.size(), 0);149 for (int i = a.vec.size() - 1; i >= 0; i--) {150 r = r * 10 + BigInt(a.vec[i]);151 int cnt = 0;152 while (!abs_less(r, b)) {153 r = abs_sub(r, b);154 cnt++;155 }156 q.vec[i] = cnt;157 }158 q.trim();159 r.trim();160 return {q, r};161 }162 // 封装有符号除法163 friend pair<BigInt, BigInt> divmod(BigInt a, BigInt b) {164 int res_q_sign = a.sign * b.sign;165 int res_r_sign = a.sign; // 余数符号与被除数一致166 pair<BigInt, BigInt> res = abs_divmod(a, b);167 res.first.sign = res_q_sign;168 res.second.sign = res_r_sign;169 res.first.trim(); // 再次 trim 确保 -0 变 0170 res.second.trim();171 return res;172 }173 BigInt operator/(const BigInt& b) const { return divmod(*this, b).first; }174 BigInt operator%(const BigInt& b) const { return divmod(*this, b).second; }175 BigInt& operator/=(const BigInt& b) { return *this = *this / b; }176 BigInt& operator%=(const BigInt& b) { return *this = *this % b; }177 BigInt operator*(int b_int) const {178 if (b_int == 0) return BigInt(0);179 BigInt b_big(b_int);180 return (*this) * b_big;181 }182 friend ostream& operator<<(ostream& os, const BigInt& a) {183 if (a.sign == -1) os << '-';184 for (int i = a.vec.size() - 1; i >= 0; i--) os << a.vec[i];185 return os;186 }187 friend istream& operator>>(istream& is, BigInt& a) {188 string s;189 if (!(is >> s)) return is;190 a = BigInt(s);191 return is;192 }193};int128输出流自定义
1#include <bits/stdc++.h>2using namespace std;3using i128 = __int128;4ostream &operator<<(ostream &os, i128 n) {5 string s;6 int f = 0;7 if(n == 0)8 s = "0";9 if(n < 0)10 {11 f = 1;12 n = -n;13 }14 while (n) {15 s += '0' + n % 10;16 n /= 10;17 }18 reverse(s.begin(), s.end());19 if(f)20 s = '-' + s;21 return os << s;22}23istream &operator>>(istream &is,i128& n)24{25 n = 0;26 string s;27 is >> s;28 int sign = 1, start = 0;29 if(s[0] == '-')30 {31 sign = -1;32 start = 1;33 }34 for (int i = start; i < s.size();i++)35 {36 n = n * 10 + s[i] - '0';37 }38 n *= sign;39 return is;40}分数四则运算
1#include <bits/stdc++.h>2using namespace std;3using i64 = long long;4template<class T>5struct Frac6{7 T num;8 T den;9 void normalize()10 {11 if (den < 0)12 {13 num = -num;14 den = -den;15 }16 T g = gcd(num, den);17 if (g != 0) { num /= g; den /= g; }18 }19 Frac(T num_, T den_) : num(num_), den(den_)20 {21 if(den < 0)22 {23 den = -den;24 num = -num;25 }26 }27 Frac() : Frac(0, 1) {}28 Frac(T num_) : Frac(num_, 1){}29 explicit operator double() const30 {31 return 1. * num / den;32 }33 Frac &operator+=(const Frac &rhs)34 {35 num = num * rhs.den + rhs.num * den;36 den *= rhs.den;37 normalize();38 return *this;39 }40 Frac &operator-=(const Frac &rhs)41 {42 num = num * rhs.den - rhs.num * den;43 den *= rhs.den;44 normalize();45 return *this;46 }47 Frac &operator*=(const Frac &rhs)48 {49 num *= rhs.num;50 den *= rhs.den;51 normalize();52 return *this;53 }54 Frac &operator/=(const Frac &rhs)55 {56 num *= rhs.den;57 den *= rhs.num;58 if(den < 0)59 {60 num = -num;61 den = -den;62 }63 normalize();64 return *this;65 }66 friend Frac operator+(Frac lhs, const Frac &rhs)67 {68 return lhs += rhs;69 }70 friend Frac operator-(Frac lhs, const Frac &rhs)71 {72 return lhs -= rhs;73 }74 friend Frac operator*(Frac lhs, const Frac &rhs)75 {76 return lhs *= rhs;77 }78 friend Frac operator/(Frac lhs, const Frac &rhs)79 {80 return lhs /= rhs;81 }82 friend Frac operator-(const Frac &a)83 {84 return Frac(-a.num, a.den);85 }86 friend bool operator==(const Frac &lhs, const Frac &rhs)87 {88 return lhs.num * rhs.den == rhs.num * lhs.den;89 }90 friend bool operator!=(const Frac &lhs, const Frac &rhs)91 {92 return lhs.num * rhs.den != rhs.num * lhs.den;93 }94 friend bool operator<(const Frac &lhs, const Frac &rhs)95 {96 return lhs.num * rhs.den < rhs.num * lhs.den;97 }98 friend bool operator>(const Frac &lhs, const Frac &rhs)99 {100 return lhs.num * rhs.den > rhs.num * lhs.den;101 }102 friend bool operator<=(const Frac &lhs, const Frac &rhs)103 {104 return lhs.num * rhs.den <= rhs.num * lhs.den;105 }106 friend bool operator>=(const Frac &lhs, const Frac &rhs)107 {108 return lhs.num * rhs.den >= rhs.num * lhs.den;109 }110 friend ostream &operator<<(ostream &os, Frac x)111 {112 T g = gcd(x.num, x.den);113 if(x.den == g)114 return os << x.num / g;115 else116 return os << x.num / g << "/" << x.den / g;117 }118};部分信息可能已经过时