#include<bits/stdc++.h> usingnamespace std; #define int long long constint Max = 0x3f3f3f3f3f3f3f3f; constint Min = -0x3f3f3f3f3f3f3f3f; constint N = 2e5+5; typedef pair<int, int>PII; int T, n, m; constint mod = 1e9 + 7; int fact[N], infact[N];
intqpow(int a, int b, int mod) { int res = 1; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res; } voidinit() { fact[0] = infact[0] = 1; fact[1] = infact[1] = 1; for (int i = 1; i < N; ++ i) { fact[i] = fact[i - 1] * i % mod; // infact[i] = qpow(fact[i], mod - 2, mod); // lg(n) 求逆元 } // 线性求逆元 for(int i = 2; i < N; i ++) { infact[i] = (mod - mod / i) * infact[mod % i] % mod; } for(int i = 2; i < N; i ++) { infact[i] = infact[i-1] * infact[i] % mod; } }
intC(int a, int b) { if(a < b || b < 0) return0; return fact[a] * infact[b] % mod * infact[a - b] % mod; }
intA(int a, int b) { if(a < b || b < 0) return0; return fact[a] * infact[a - b] % mod; }
intqpow(int a, int b, int p) { int res = 1; while (b) { if (b & 1) res = (LL)res * a % p; a = (LL)a * a % p; b >>= 1; } return res; } intc(int a, int b, int p)// 调用组合数时候就一定保证a和b是小于p的了,所以a和b定为int { if (b > a) return0; // 按照公式计算 int res = 1; for (int i = a - b + 1, j = 1; j <= b; ++ i, ++ j) { res = (LL)res * i % p; // 保证b是小于p的,因为p质数,所以1到b的所有数都一定与p互质,所以计算逆元可以采用费马小定理 res = (LL)res * qpow(j, p - 2, p) % p; // 理解原理需要用到“预处理中间值-代码实现”中提到的等式 } return res; } intlucas(LL a, LL b, int p) { if (a < p && b < p) returnc(a, b, p); return (LL)c(a % p, b % p, p) * lucas(a / p, b / p, p) % p; // %p保证运算后的结果小于p,无法再使用lucas优化了,所以直接调用组合式函数即可,但/运算则无法保证 } intmain() { cin >> n; while (n --) { int p; LL a, b; cin >> a >> b >> p; cout << lucas(a, b, p) << endl; } return0; }
intqpow(int a, int b, int mod) { int res = 1; while (b) { if (b & 1) res = (LL)res * a % mod; a = (LL)a * a % mod; b >>= 1; } return res; } intmain() { int n; cin >> n; int res = 1; for (int i = n + 1, j = 1; j <= n; ++ i, ++ j) { res = (LL)res * i % mod; res = (LL)res * qpow(j, mod - 2, mod) % mod; } res = (LL)res * qpow(n + 1, mod - 2, mod) % mod; cout << res << endl; return0; }
#include<bits/stdc++.h> usingnamespace std; #define int long long constint N = 2e5+5; int n, m, k; int p[N], a[N], lg[N]; int f[N][20], c[N][20]; structnode { int x, y, z; }tr[N];
#include<bits/stdc++.h> usingnamespace std; constint N = 3e5+5; typedeflonglong ll; typedef pair<int, int>PII; int n, m, k; int T; queue<int>q; structnode { int e, w; }; vector<node>v[N]; bool st[N]; int dis[N];
voidspfa() { for(int i = 1; i <= 3*n; i ++) dis[i] = INT_MIN; dis[1] = 0; q.push(1); st[1] = true;
while(q.size()) { int t = q.front(); q.pop(); st[t] = false; for(int i = 0; i < v[t].size(); i ++) { int z = v[t][i].e; if(dis[z] < dis[t] + v[t][i].w) { dis[z] = dis[t] + v[t][i].w; if(!st[z]) { q.push(z); st[z] = true; } } } } } /*分层图,三层 */ voidsolve() { cin >> n >> m; for(int i = 1; i <= n; i ++) { int x; cin >> x; v[i].push_back({i + n*1, -x}); v[i+n*1].push_back({i + n*2, x}); } while(m --) { int a, b, c; cin >> a >> b >> c; v[a].push_back({b, 0}); v[a+n*1].push_back({b+n*1, 0}); v[a+n*2].push_back({b+n*2, 0}); if(c==2) v[b].push_back({a, 0}), v[b+n*1].push_back({a+n*1, 0}), v[b+n*2].push_back({a+n*2, 0}); }
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5+5; typedeflonglong ll; typedef pair<int, int>PII; int n, m, k; int T; queue<int>q; int dis[N], cnt[N]; bool st[N]; structnode { int e, w; }; vector<node>v[N];
#include<bits/stdc++.h> usingnamespace std; #define int long long #define PII pair<int, int> constint N = 1e5+5; int n, m, k; int dis[N]; bool st[N]; priority_queue<PII, vector<PII>, greater<PII>>q; vector<PII>v[N];
voiddijkstra() { q.push({0, 0}); dis[0] = 0; while(q.size()) { PII t = q.top(); q.pop(); int t1 = t.first, t2 = t.second; if(st[t2]) continue; st[t2] = true; for(int i = 0; i < v[t2].size(); i ++) { int z = v[t2][i].first; if(dis[z] > dis[t2] + v[t2][i].second) { dis[z] = dis[t2] + v[t2][i].second; q.push({dis[z], z}); } } } }
signedmain() { ios::sync_with_stdio(false), cin.tie(0); memset(dis, 0x3f, sizeof dis); cin >> n; int a[3]; cin >> a[0] >> a[1] >> a[2]; sort(a, a + 3); if(a[0]==1) { cout << n; return0; } for(int i = 0; i < a[0]; i ++) { v[i].push_back({(i+a[1])%a[0], a[1]}); v[i].push_back({(i+a[2])%a[0], a[2]}); } dijkstra(); int ans = 0; for(int i = 0; i < a[0]; i ++) { if(dis[i]<=n-1) ans+=(n-1-dis[i])/a[0]+1; } cout << ans << "\n"; return0; }
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5+5; typedeflonglong ll; int r1[505], r[505]; int cnt[505], path[505]; int dis[505]; int v[505][505]; bool st[505]; int n, m, k, s, d; int T;
#include<bits/stdc++.h> usingnamespace std; #define int long long constint N = 2e5+5; int n, m, s, t; int h[N], e[N], ne[N], idx; int cf[N], mf[N], pre[N]; // 分别是这个边的容量、s~v的流量上限、v的前驱边 queue<int>q;
voidadd(int a, int b, int c) { e[idx] = b, cf[idx] = c, ne[idx] = h[a], h[a] = idx ++; }
intbfs() { for(int i = 1; i <= n; i ++) mf[i] = 0; while(q.size()) q.pop(); q.push(s); mf[s] = 1e18; while(q.size()) { int u = q.front(); q.pop(); for(int i = h[u]; i != -1; i = ne[i]) { int v = e[i]; if(mf[v] == 0 && cf[i]) { mf[v] = min(mf[u], cf[i]); pre[v] = i; q.push(v); if(v == t) returntrue; } } } returnfalse; }
intEK() { int flow = 0; while(bfs()) { int v = t; while(v != s) { int i = pre[v]; cf[i] -= mf[t]; cf[i^1] += mf[t]; v = e[i^1]; } flow += mf[t]; } return flow; } signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m >> s >> t; for(int i = 1; i <= n; i ++) h[i] = -1; for(int i = 0; i < m; i ++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); add(b, a, 0); } cout << EK() << '\n'; }
#include<bits/stdc++.h> usingnamespace std; #define int long long constint N = 2e5+5; int n, m, s, t; int h[N], e[N], ne[N], idx; int cf[N]; // 边的容量 int d[N]; // 点深度,做分层图 int cur[N]; // 当前弧
queue<int>q;
voidadd(int a, int b, int c) { e[idx] = b, cf[idx] = c, ne[idx] = h[a], h[a] = idx ++; }
intbfs()//对点分层,找增广路 { for(int i = 1; i <= n; i ++) d[i] = 0; while(q.size()) q.pop(); q.push(s); d[s] = 1; while(q.size()) { int u = q.front(); q.pop(); for(int i = h[u]; i != -1; i = ne[i]) { int v = e[i]; if(d[v] == 0 && cf[i]) { d[v] = d[u] + 1; q.push(v); if(v == t) returntrue; } } } returnfalse; }
intdfs(int u, int mf)// 多路增广 { if(u == t) return mf; int sum = 0; for(int i = cur[u]; ~i; i = ne[i]) { cur[u] = i; // 当前弧优化 int v = e[i]; if(d[v] == d[u] + 1 && cf[i]) { int f = dfs(v, min(mf, cf[i])); cf[i] -= f; cf[i^1] += f; // 更新残留网 sum += f; // 累加u的流出流量 mf -= f; // 减少u的剩余流量 if(mf == 0) break; //余量优化 } } if(sum == 0) d[u] = 0; return sum; }
signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m >> s >> t; for(int i = 1; i <= n; i ++) h[i] = -1; for(int i = 0; i < m; i ++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); add(b, a, 0); } cout << dinic() << '\n'; }
#include<bits/stdc++.h> usingnamespace std; constint N = 5e5+5; int n, m, s; int dep[N], fa[N][20]; vector<int>v[N];
voiddfs(int u, int f) { dep[u] = dep[f] + 1; fa[u][0] = f; for(int i = 1; i < 20; i ++) { fa[u][i] = fa[fa[u][i-1]][i-1]; } for(int e : v[u]) { if(e != f) dfs(e, u); } }
intlca(int x, int y) { if(dep[x] < dep[y]) swap(x, y); // 让 x 的深度大于等于 y for(int i = 19; i >= 0; i --) { if(dep[fa[x][i]] >= dep[y]) x = fa[x][i]; // 跳到同一深度 } if(x == y) return x; for(int i = 19; i >= 0; i --) // 一块向上跳,直到父节点相同 { if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; } return fa[x][0]; }
signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m >> s; for(int i = 1; i < n; i ++) { int x, y; cin >> x >> y; v[x].push_back(y); v[y].push_back(x); } dfs(s, 0); for(int i = 1; i <= m; i ++) { int x, y; cin >> x >> y; cout << lca(x, y) << '\n'; } return0; }
#include<bits/stdc++.h> usingnamespace std; constint N = 5e5+5; typedef pair<int, int>PII; int n, m, s; vector<int>v[N]; vector<PII>q[N]; int p[N], ans[N]; bool st[N];
intfind(int x) { if(x == p[x]) return x; return p[x] = find(p[x]); } voidtj(int u) { st[u] = true; for(int e : v[u]) { if(!st[e]) { tj(e); p[e] = u; } } for(PII it : q[u]) { int t1 = it.first, t2 = it.second; if(st[t1]) ans[t2] = find(t1); } } signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m >> s; for(int i = 1; i < n; i ++) { int x, y; cin >> x >> y; v[x].push_back(y); v[y].push_back(x); } for(int i = 1; i <= m; i ++) // 离线处理 { int x, y; cin >> x >> y; q[x].push_back({y, i}); q[y].push_back({x, i}); } for(int i = 1; i <= n; i ++) p[i] = i; // 并查集初始化不要忘 tj(s); for(int i = 1; i <= m; i ++) { cout << ans[i] << '\n'; } }
#include<bits/stdc++.h> usingnamespace std; constint N = 5e5+5; int n, m, s; vector<int>e[N]; // 子树大小,父节点,重链顶点,重儿子,深度 int sz[N], fa[N], top[N], son[N], dep[N];
voiddfs2(int u, int t) { top[u] = t; if(!son[u]) return; dfs2(son[u], t); for(int v : e[u]) { if(v == fa[u] || v == son[u]) continue; dfs2(v, v); } }
intlca(int u, int v) { while(top[u] != top[v]) { if(dep[top[u]] < dep[top[v]]) swap(u, v); //始终让 u 最深 u = fa[top[u]]; } return dep[u] < dep[v] ? u : v; }
signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m >> s; // n 个点, m 个询问, s 是根节点 for(int i = 1; i < n; i ++) { int x, y; cin >> x >> y; e[x].push_back(y); e[y].push_back(x); } dfs1(s, 0); dfs2(s, s); for(int i = 1; i <= m; i ++) { int x, y; cin >> x >> y; int tt = lca(x, y); cout << tt << '\n'; } return0; }
#include<bits/stdc++.h> usingnamespace std; #define int long long constint Max = 0x3f3f3f3f3f3f3f3f; constint Min = -0x3f3f3f3f3f3f3f3f; constint N = 2e5+5; typedef pair<int, int>PII; int T, n, m; vector<int>v[N], nv[N]; int a[N]; int dfn[N], tot = 0, low[N], sk[N], cnt, top; int scc[N], w[N], sz[N]; bool vis[N]; int din[N], res[N]; queue<int>q;
for(int i = 1; i <= m; i ++) { int x, y; cin >> x >> y; v[x].push_back(y); } for(int i = 1; i <= n; i ++) { if(!dfn[i]) tj(i); } for(int i = 1; i <= n; i ++) // 缩点建新图 { for(int j : v[i]) { if(scc[i] != scc[j]) { nv[scc[i]].push_back(scc[j]); din[scc[j]] ++; } } }
for(int i = 1; i <= cnt; i ++) { res[i] = w[i]; if(!din[i]) q.push(i); } while(q.size()) // 拓扑排序求最大权值路径 { int t = q.front(); q.pop(); for(int e : nv[t]) { din[e] --; res[e] = max(res[e], res[t] + w[e]); if(din[e] == 0) { q.push(e); } } } int ans = 0; for(int i = 1; i <= n; i ++) { ans = max(ans, res[i]); } cout << ans << '\n'; return0; }
割点
割点:对于一个无向图,如果把一个点删除后,连通块的个数增加了,那么这个点就是割点(又称割顶)。
割点判定法则:
(1)如果 x 不是根节点,当搜索树上存在 x 的一个子节点 y,满足 low[y]≥dfn[x],那么 x 就是割点。
(2)如果 x 是根节点,当搜索树上存在至少两个子节点 y1,y2,满足上述条件,那么 x 就是割点。
#include<bits/stdc++.h> usingnamespace std; constint N = 2e5+5; int n, m; vector<int>v[N]; int res = 0, ls[N]; bool vis[N]; int dfn[N], low[N], tot = 0, rt;
signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m; for(int i = 1; i <= m; i ++) { int x, y; cin >> x >> y; v[x].push_back(y); v[y].push_back(x); } for(int i = 1; i <= n; i ++) { if(!dfn[i]) { rt = i; tj(i); } }
for(int i = 1; i <= n; i ++) if(vis[i]) ls[++res] = i;
cout << res << '\n'; for(int i = 1; i <= res; i ++) cout << ls[i] << " \n"[i == n]; return0; }
割边
割边:对于一个无向图,如果删掉一条边后图中的连通块个数增加了,则称这条边为桥或者割边。
割边判定法则:当搜索树上存在 x 的一个子节点 y,满足 low[y]>dfn[x],则 (x,y) 这条边就是割边。
#include<bits/stdc++.h> usingnamespace std; constint N = 2e5+5; int n, m; int h[N], e[N], ne[N], idx = 1; // 建图编号从1开始,h数组不用初始化-1了 int dfn[N], low[N], tot = 0; set<pair<int, int>>se;
voidadd(int a, int b) { e[++ idx] = b, ne[idx] = h[a], h[a] = idx; }
voidtj(int u, int x) { dfn[u] = low[u] = ++tot; for(int i = h[u]; i; i = ne[i]) { int t = e[i]; if(!dfn[t]) { tj(t, i); low[u] = min(low[u], low[t]); if(low[t] > dfn[u]) // 题目要求输出最小的字典序,所以用的set { int a = t, b = u; if(a > b) swap(a, b); se.insert({a, b}); } } elseif(i != (x ^ 1)) { low[u] = min(low[u], dfn[t]); } } }
signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m; for(int i = 1; i <= m; i ++) { int x, y; cin >> x >> y; add(x, y); add(y, x); } for(int i = 1; i <= n; i ++) { if(!dfn[i]) tj(i, 0); } for(auto it : se) { cout << it.first << " " << it.second << '\n'; } return0; }
eDCC 缩点(边双连通分量)
边双连通分量的含义:无向图中极大的不包含割边的连通块
如果求边双连通分量内点的数量,只需要遍历 scc 即可,求边的数量则去遍历 bri
1 2 3 4 5 6 7 8 9 10 11 12 13
for(int i = 2; i <= idx; i += 2) { if(bri[i]) // 建图 { int x = scc[e[i]], y = scc[e[i ^ 1]]; v[x].push_back(y); v[y].push_back(x); } else { sz[scc[e[i]]] ++; // 存的是编号为scc[e[i]]的边双连通分量内边的数量 } }
#include<bits/stdc++.h> usingnamespace std; constint N = 2e5+5; int n, m; int e[N], ne[N], h[N], idx = 1; int dfn[N], low[N], tot; bool bri[N]; int sk[N], top; int dcc[N], cnt = 0, du[N];
voidadd(int x, int y) { e[++ idx] = y, ne[idx] = h[x], h[x] = idx; }
voidtj(int u, int id) { dfn[u] = low[u] = ++tot; sk[++top] = u; for(int i = h[u]; i; i = ne[i]) { int t = e[i]; if(!dfn[t]) { tj(t, i); low[u] = min(low[u], low[t]); if(low[t] > dfn[u]) // 割边操作,把割边记录下来(也就是桥) { bri[i] = true; bri[i ^ 1] = true; } } elseif(i != (id ^ 1)) { low[u] = min(low[u], dfn[t]); } } if(dfn[u] == low[u]) { int y; cnt ++; do{ y = sk[top --]; dcc[y] = cnt; }while(y != u); } }
signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m; for(int i = 1; i <= m; i ++) { int x, y; cin >> x >> y; add(x, y); add(y, x); }
for(int i = 1; i <= n; i ++) { if(!dfn[i]) tj(i, 0); }
for(int i = 2; i <= idx; i ++) { if(bri[i]) { du[dcc[e[i]]] ++; // 注意这里不要写成了 du[e[i]] ++ } } int res = 0; for(int i = 1; i <= cnt; i ++) { if(du[i] == 1) res ++; } cout << (res + 1) / 2 << '\n'; return0; }
#include<bits/stdc++.h> usingnamespace std; #define int long long constint N = 1e6+5; int n, m; int e[N], ne[N], h[N], idx = 1, w[N]; int dfn[N], low[N], tot; bool bri[N]; int sk[N], top; int dcc[N], cnt = 0, du[N]; int ans = 0, res = 0; voidadd(int x, int y, int z)// 编号i的边,两端点是e[i]和e[i^1] { e[++ idx] = y, ne[idx] = h[x], w[idx] = z, h[x] = idx; }
voidtj(int u, int id) { dfn[u] = low[u] = ++tot; sk[++top] = u; for(int i = h[u]; i; i = ne[i]) { int t = e[i]; if(!dfn[t]) { tj(t, i); low[u] = min(low[u], low[t]); if(low[t] > dfn[u]) { bri[i] = true; bri[i ^ 1] = true; } } elseif(i != (id ^ 1)) { low[u] = min(low[u], dfn[t]); } } if(dfn[u] == low[u]) { int y; cnt ++; do{ y = sk[top --]; dcc[y] = cnt; }while(y != u); } } vector<int>v[N]; int sz[N];
voiddfs(int u, int f) { for(int it : v[u]) { if(it == f) continue; dfs(it, u); sz[u] += sz[it] + 1; } }
signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m; for(int i = 1; i <= m; i ++) { int x, y, z; cin >> x >> y >> z; add(x, y, z); add(y, x, z); res += z; } if(m % 2 == 0) { cout << res << '\n'; return0; } for(int i = 1; i <= n; i ++) { if(!dfn[i]) tj(i, 0); } for(int i = 2; i <= idx; i += 2) // i和(i^1)是同一条边,计算一条就行 { if(bri[i]) { int t1 = dcc[e[i]], t2 = dcc[e[i^1]]; // 建立新图的时候,一定要用连通块编号 v[t1].push_back(t2); v[t2].push_back(t1); } else { sz[dcc[e[i]]] ++; sz[dcc[e[i^1]]] ++; ans = max(ans, res - w[i]); } } for(int i = 1; i <= cnt; i ++) sz[i] /= 2; // 统计的是每个连通块内边的数量,每个边被统计了两边,所以除以2 dfs(1, 0); for(int i = 2; i <= idx; i += 2) { if(bri[i]) { int t1 = dcc[e[i]], t2 = dcc[e[i^1]]; int zz = min(sz[t1], sz[t2]); if(zz % 2 == 0) ans = max(ans, res - w[i]); } } cout << ans << '\n'; }
#include<bits/stdc++.h> usingnamespace std; constint N = 2e5+5; int n, m; int rt, id[N], cnt, num; int dfn[N], low[N], tot; stack<int>sk; vector<int>v[N], nv[N], dcc[N]; bool cut[N];
#include<bits/stdc++.h> usingnamespace std; #define int long long constint Max = 0x3f3f3f3f3f3f3f3f; constint Min = -0x3f3f3f3f3f3f3f3f; constint N = 4e5+5; typedef pair<int, int>PII; int n, m; int idx = 1, e[N], ne[N], h[N], w[N]; int sz[N]; bool bri[N]; vector<int>v[N];
voidadd(int a, int b, int c) { e[++ idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx; }
int dfn[N], low[N], tot = 0, sk[N], cnt = 0, top = 0, scc[N];
voidtj(int u, int x) { dfn[u] = low[u] = ++ tot; sk[++ top] = u; for(int i = h[u]; i; i = ne[i]) { int t = e[i]; if(!dfn[t]) { tj(t, i); low[u] = min(low[u], low[t]); if(low[t] > dfn[u]) { bri[i] = true; bri[i ^ 1] = true; } } elseif(i != (x ^ 1)) { low[u] = min(low[u], dfn[t]); } } if(low[u] == dfn[u]) { int x; ++ cnt; do{ x = sk[top --]; scc[x] = cnt; }while(x != u); } } voiddfs(int u, int f) { for(int j : v[u]) { if(j == f) continue; dfs(j, u); sz[u] += sz[j] + 1; } } signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m; int res = 0; for(int i = 1; i <= m; i ++) { int x, y, z; cin >> x >> y >> z; add(x, y, z); add(y, x, z); res += z; } if(m % 2 == 0) { cout << res << '\n'; return0; } for(int i = 1; i <= n; i ++) { if(!dfn[i]) tj(i, 0); } int ans = 0; for(int i = 2; i <= idx; i += 2) { if(bri[i]) { int x = scc[e[i]], y = scc[e[i ^ 1]]; v[x].push_back(y); v[y].push_back(x); } else { sz[scc[e[i]]] ++; ans = max(ans, res - w[i]); } } dfs(1, 0); for(int i = 2; i <= idx; i += 2) { if(bri[i]) { int x = sz[scc[e[i]]], y = sz[scc[e[i ^ 1]]]; x = min(x, y); if(x % 2 == 0) { ans = max(ans, res - w[i]); } } } cout << ans << '\n'; }
voidupdata(int x, int l, int r, int u) { if(l == x && r == x) { tr[u] ++; return; } int mid = l + r >> 1; if(x <= mid) updata(x, l, mid, u << 1); elseupdata(x, mid + 1, r, u << 1 | 1); pushup(u); }
intquery(int x, int y, int l, int r, int u) { if(l >= x && r <= y) { return tr[u]; } int mid = l + r >> 1; int res = 0; if(x <= mid) res += query(x, y, l, mid, u << 1); if(y > mid) res += query(x, y, mid + 1, r, u << 1 | 1); return res; }
voidsolve() { cin >> n >> m; for(int i = 1; i <= n; i ++) { cin >> a[i]; s[i] = s[i - 1] + a[i]; } for(int i = 1; i <= n; i ++) { v.push_back(s[i]); v.push_back(s[i] + m); } sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); int n2 = v.size(); int ans = 0; for(int i = 1; i <= n; i ++) { int x = getid(s[i]); ans += query(x + 1, n2, 1, n2, 1); int y = getid(s[i] + m); updata(y, 1, n2, 1); if(s[i] < m) ans ++; } cout << ans << '\n'; }
#include<bits/stdc++.h> usingnamespace std; #define int long long constint N = 5e5+5; int T, n, m, sz = 0, ans = 0; vector<int> v; structnode { int l, r, len, tot; }tr[N * 4];
structblde { int x, x2, y, f; }bl[N * 4];
boolcmp(blde aa, blde bb) { return aa.y < bb.y; } voidbuild(int u, int l, int r) { tr[u] = {l, r, 0, 0}; if(l == r) return; int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); }
int n, m; int s[N]; int tr[M][2], max_id[M]; int root[N], idx;
voidinsert(int i, int k, int p, int q) { if (k < 0) { max_id[q] = i; return; } int v = s[i] >> k & 1; if (p) tr[q][v ^ 1] = tr[p][v ^ 1]; tr[q][v] = ++ idx; insert(i, k - 1, tr[p][v], tr[q][v]); max_id[q] = max(max_id[tr[q][0]], max_id[tr[q][1]]); }
intquery(int root, int C, int L) { int p = root; for (int i = 23; i >= 0; i -- ) { int v = C >> i & 1; if (max_id[tr[p][v ^ 1]] >= L) p = tr[p][v ^ 1]; else p = tr[p][v]; }
intbuild(int l, int r) { int p = ++ idx; if (l == r) return p; int mid = l + r >> 1; tr[p].l = build(l, mid), tr[p].r = build(mid + 1, r); return p; }
intupdata(int p, int l, int r, int x) { int q = ++ idx; tr[q] = tr[p]; if (l == r) { tr[q].cnt ++ ; return q; } int mid = l + r >> 1; if (x <= mid) tr[q].l = updata(tr[p].l, l, mid, x); else tr[q].r = updata(tr[p].r, mid + 1, r, x); tr[q].cnt = tr[tr[q].l].cnt + tr[tr[q].r].cnt; return q; }
intquery(int q, int p, int l, int r, int k) { if (l == r) return r; int cnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt; int mid = l + r >> 1; if (k <= cnt) returnquery(tr[q].l, tr[p].l, l, mid, k); elsereturnquery(tr[q].r, tr[p].r, mid + 1, r, k - cnt); }
signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1; i <= n; i ++ ) { cin >> a[i]; v.push_back(a[i]); }
#include<bits/stdc++.h> usingnamespace std; #define int long long constint Max = 0x3f3f3f3f3f3f3f3f; constint Min = -0x3f3f3f3f3f3f3f3f; constint N = 2e5+5; typedef pair<int, int>PII; int T, n, m; int sz[N], son[N], fa[N]; vector<int>v[N]; int col[N], cnt[N], ans[N]; int sum, mx;
voidadd(int u, int f, int son) { cnt[col[u]] ++; if(cnt[col[u]] > mx) { mx = cnt[col[u]]; sum = col[u]; } elseif(cnt[col[u]] == mx) { sum += col[u]; } for(int e : v[u]) { if(e == f || e == son) continue; add(e, u, son); } }
voidsub(int u, int f) { cnt[col[u]] --; for(int e : v[u]) { if(e == f) continue; sub(e, u); } }
voiddsu(int u, int f, int c) { for(int e : v[u]) { if(e == f || e == son[u]) continue; dsu(e, u, 0); } if(son[u]) dsu(son[u], u, 1); add(u, f, son[u]); ans[u] = sum; if(!c) sub(u, f), sum = mx = 0; }
signedmain() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n; for(int i = 1; i <= n; i ++) { cin >> col[i]; } for(int i = 1; i < n; i ++) { int a, b; cin >> a >> b; v[a].push_back(b); v[b].push_back(a); } dfs(1, 0); dsu(1, 0, 0); for(int i = 1; i <= n; i ++) cout << ans[i] << " "; }
Arpa has a rooted tree (connected acyclic graph) consisting of n vertices. The vertices are numbered 1 through n, the vertex 1 is the root. There is a letter written on each edge of this tree. Mehrdad is a fan of Dokhtar-kosh things. He call a string Dokhtar-kosh, if we can shuffle the characters in string such that it becomes palindrome.
He asks Arpa, for each vertex v, what is the length of the longest simple path in subtree of v that form a Dokhtar-kosh string.
The first line contains integer n (1 ≤ n ≤ 5⋅105) — the number of vertices in the tree.
(n - 1) lines follow, the i-th of them contain an integer pi+ 1 and a letter ci+ 1 (1 ≤ pi+ 1 ≤ i, ci+ 1 is lowercase English letter, between a and v, inclusively), that mean that there is an edge between nodes pi+ 1 and i + 1 and there is a letter ci+ 1written on this edge.
Print n integers. The i-th of them should be the length of the longest simple path in subtree of the i-th vertex that form a Dokhtar-kosh string.
#include<bits/stdc++.h> usingnamespace std; #define int long long constint N = 5e5+5; typedef pair<int, int>PII; int T, n, m; vector<PII>v[N]; int sz[N], dep[N], dis[N], fa[N], son[N], ans[N]; int ju[1 << 22]; // ju[i] 存的是值为 i 时的最大深度 voiddfs(int u, int f) { sz[u] = 1; dep[u] = dep[f] + 1; for(auto it : v[u]) { int t = it.first, w = it.second; if(t == f) continue; fa[t] = u; dis[t] = dis[u] ^ w; dfs(t, u); sz[u] += sz[t]; if(sz[son[u]] < sz[t]) son[u] = t; } }
voidupdata(int u, int f) { ju[dis[u]] = max(ju[dis[u]], dep[u]); for(auto it : v[u]) { int t = it.first; if(t == f) continue; updata(t, u); } }
voidadd(int u, int f, int son, int to)// to 是当前子树的根节点 { // dis[u] ^ dis[v] = 0 if(ju[dis[u]]) ans[to] = max(ans[to], ju[dis[u]] + dep[u] - 2 * dep[to]); // dis[u] ^ dis[v] = 1 << k; for(int i = 0; i < 22; i ++) if(ju[dis[u] ^ (1 << i)]) ans[to] = max(ans[to], dep[u] + ju[dis[u] ^ (1 << i)] - 2 * dep[to]); // 头节点算完就能立刻更新,后面算子树的时候先算完子树才能更新,不然就乱了 if(u == to) { ju[dis[u]] = max(ju[dis[u]], dep[u]); } for(auto it : v[u]) { int t = it.first; if(t != f) ans[u] = max(ans[u], ans[t]); // 将之前的子树答案更新到根节点上,再去算根节点 if(t == f || t == son) continue; add(t, u, son, to); } // 子树被计算完答案后才能将其权值记录,并将其节点全部更新,不能避开轻子树内的重儿子 if(fa[u] == to) { updata(u, f); } }
voidsub(int u, int f) { ju[dis[u]] = 0; for(auto it : v[u]) { int t = it.first; if(t == f) continue; sub(t, u); } }
voiddsu(int u, int f, int z) { for(auto it : v[u]) { int t = it.first; if(t == f || t == son[u]) continue; dsu(t, u, 0); } if(son[u]) dsu(son[u], u, 1); add(u, f, son[u], u); // 计算每个子树的答案 if(!z) sub(u, f); // 清空轻子树 }
voidsolve() { cin >> n; for(int i = 2; i <= n; i ++) { int x; char c; cin >> x >> c; int w = 1 << (c - 'a'); v[x].push_back({i, w}); v[i].push_back({x, w}); } dfs(1, 0); dsu(1, 0, 0); for(int i = 1; i <= n; i ++) { cout << ans[i] << " \n"[i == n]; } }
#include<bits/stdc++.h> usingnamespace std; constint N = 10010, S = 55, M = 1000010; int n; int tr[N * S][26], cnt[N * S], idx; string s; int q[N * S], ne[N * S];
voidinsert() { int p = 0; for (int i = 0; s[i]; i ++ ) { int t = s[i] - 'a'; if (!tr[p][t]) tr[p][t] = ++ idx; p = tr[p][t]; } cnt[p] ++ ; }
voidbuild() { int hh = 0, tt = -1; for (int i = 0; i < 26; i ++ ) if (tr[0][i]) q[ ++ tt] = tr[0][i];
while (hh <= tt) { int t = q[hh ++ ]; for (int i = 0; i < 26; i ++ ) { int p = tr[t][i]; if (!p) tr[t][i] = tr[ne[t]][i]; else { ne[p] = tr[ne[t]][i]; q[ ++ tt] = p; } } } }