teamnote history merge

This commit is contained in:
2026-06-03 09:36:52 +09:00
parent f50ed902fe
commit 7176febe54
142 changed files with 13243 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
ok = true; // 1<=i&&i<=n : $x$, n+1<=i&&i<=2*n : $!x$
forr(i, n) {
if (scn[i] == scn[i+n]) ok = false;
ans[i] = (scn[i] < scn[i+n]);
}

View File

@@ -0,0 +1,13 @@
vector<int> sideadj[N];
int selby[M];
int chk[M], c;
bool matching(int s) {
for(auto i : sideadj[s]) {
if(chk[i] == c) continue;
chk[i] = c;
if(selby[i] and !matching(selby[i])) continue;
selby[i] = s;
return true;
}
return false;
}

View File

@@ -0,0 +1,69 @@
struct Edge {
int to, cap, now;
Edge* rev;
Edge(int to,int cap):to(to), cap(cap), now(0){}
int left(){return cap - now;}
void flow(int f){now += f; rev->now -= f;}
void reset(){now = 0;}
};
vector<Edge*> adj[N];
int lv[N]; bool chk[N];
bool bfs(int S, int T) {
queue<int> q;
q.push(S); lv[S] = 0; chk[S] = true;
while(!q.empty()) {
int s = q.front(); q.pop();
for(auto i : adj[s]) {
if(i->left() and !chk[i->to]) {
lv[i->to] = lv[s]+1; chk[i->to] = true;
q.push(i->to);
}
}
}
return chk[T];
}
Edge* hist[N]; int last[N];
bool dfs(int s, int T) {
if(s == T) return true;
for(int &j=last[s]; j < adj[s].size(); j++) {
int i = adj[s][j]->to;
if(adj[s][j]->left() == 0 or lv[i] != lv[s]+1) continue;
hist[i] = adj[s][j];
if(dfs(i, T)) return true;
}
return false;
}
ll flow(int S,int T) {
ll ans = 0;
while(bfs(S, T)) {
while(dfs(S, T)) {
int m = 2e9;
int now = T;
while(S != now) {
m = min(m, hist[now]->left());
now = hist[now]->rev->to;
}
now = T;
while(S != now)
hist[now]->flow(m), now = hist[now]->rev->to;
ans += m;
}
memset(last, 0, sizeof last);
memset(chk, 0, sizeof chk);
}
return ans;
}
// isDir : isDirected => 양방향 간선이면 false
void connect(int from, int to, int cap, bool isDir = true) {
Edge *fw, *bw;
fw = new Edge(to, cap);
bw = new Edge(from, !isDir ? cap : 0);
fw->rev = bw; bw->rev = fw;
adj[from].push_back(fw);
adj[to].push_back(bw);
}

View File

@@ -0,0 +1,51 @@
// https://ideone.com/aO6cH4
namespace dtree{ // by cki86201
vector<int> E[N], RE[N], rdom[N];
int S[N], RS[N], cs;
int par[N], val[N], sdom[N], rp[N], dom[N];
void clear(int n) { cs = 0;
for(int i=0;i<=n;i++) {
par[i] = val[i] = sdom[i] = rp[i] = dom[i] = S[i] = RS[i] = 0;
E[i].clear(); RE[i].clear(); rdom[i].clear();
}
}
void add_edge(int x, int y) { E[x].push_back(y); }
void Union(int x, int y) { par[x] = y; }
int Find(int x, int c = 0) {
if(par[x] == x) return c ? -1 : x;
int p = Find(par[x], 1);
if(p == -1) return c ? par[x] : val[x];
if(sdom[val[x]] > sdom[val[par[x]]]) val[x] = val[par[x]];
par[x] = p;
return c ? p : val[x];
}
void dfs(int x) {
RS[ S[x] = ++cs ] = x;
par[cs] = sdom[cs] = val[cs] = cs;
for(int e : E[x]) {
if(S[e] == 0) dfs(e), rp[S[e]] = S[x];
RE[S[e]].push_back(S[x]);
}
}
int solve(int s, int *up) { // Calculate idoms
dfs(s);
for(int i=cs;i;i--) {
for(int e : RE[i]) sdom[i] = min(sdom[i], sdom[Find(e)]);
if(i > 1) rdom[sdom[i]].push_back(i);
for(int e : rdom[i]) {
int p = Find(e);
if(sdom[p] == i) dom[e] = i;
else dom[e] = p;
}
if(i > 1) Union(i, rp[i]);
}
for(int i=2;i<=cs;i++) if(sdom[i] != dom[i]) dom[i] = dom[dom[i]];
for(int i=2;i<=cs;i++) up[RS[i]] = RS[dom[i]];
return cs;
}
} // namespace dtree
int par[N];
dtree::add_edge(a, b); // a -> b
int cnt = dtree::solve(s, par);
// cnt : s에서 도달할 수 있는 정점, par: dominator tree의 par

View File

@@ -0,0 +1,67 @@
struct Edge {
int to, cap, now;
ll cost;
Edge* rev;
Edge(int to,int cap, ll cost)
:to(to), cap(cap), now(0), cost(cost){}
int left(){return cap - now;}
ll flow(int f)
{now += f; rev->now -= f; return cost * f;}
void reset(){now = 0;}
};
vector<Edge*> adj[N];
Edge* hist[N]; ll dist[N]; bool inQueue[N], chk[N];
bool spfa(int s, int t) {
memset(dist, 0, sizeof(dist));
memset(chk, 0, sizeof(chk)); chk[s] = true;
queue<int> q;
memset(inQueue, 0, sizeof(inQueue));
q.push(s); inQueue[s] = true;
while(!q.empty()) {
int now = q.front();
q.pop(); inQueue[now] = false;
for(auto e : adj[now]) {
int next = e->to;
if(e->left() > 0 and
(chk[next] == false
or dist[next] > dist[now] + e->cost)) {
chk[next] = true;
dist[next] = dist[now] + e->cost;
hist[next] = e;
if(!inQueue[next])
q.push(next), inQueue[next] = true;
}
}
}
return chk[t];
}
// cost가 들어가면 항상 단방향만 가능하다. (양방향 : 2번 connect)
void connect(int from, int to, int cap, ll cost) {
Edge *fw, *bw;
fw = new Edge(to, cap, cost);
bw = new Edge(from, 0, -cost);
fw->rev = bw; bw->rev = fw;
adj[from].push_back(fw);
adj[to].push_back(bw);
}
//maximum matching & minimum cost
pair<ll, ll> flow(int S,int T) {
ll ans = 0; ll cost = 0;
while(spfa(S, T)) {
int m = 2e9;
int now = T;
while(S != now) {
m = min(m, hist[now]->left());
now = hist[now]->rev->to;
}
now = T;
while(S != now) {
cost += hist[now]->flow(m);
now = hist[now]->rev->to;
}
ans += m;
}
return {ans, cost};
}

View File

@@ -0,0 +1,74 @@
// From https://github.com/koosaga/olympiad
// matching_short.cpp
const int MAXN = 2020 + 1;
// 1-based Vertex index
int vis[MAXN], par[MAXN], orig[MAXN], match[MAXN], aux[MAXN], t, N;
vector<int> conn[MAXN];
queue<int> Q;
void addEdge(int u, int v) { conn[u].push_back(v); conn[v].push_back(u); }
void init(int n) {
N = n; t = 0;
for(int i=0; i<=n; ++i) {
conn[i].clear();
match[i] = aux[i] = par[i] = 0;
}
}
void augment(int u, int v) {
int pv = v, nv;
do {
pv = par[v]; nv = match[pv];
match[v] = pv; match[pv] = v;
v = nv;
} while(u != pv);
}
int lca(int v, int w) {
++t;
while(true) {
if(v) {
if(aux[v] == t) return v; aux[v] = t;
v = orig[par[match[v]]];
}
swap(v, w);
}
}
void blossom(int v, int w, int a) {
while(orig[v] != a) {
par[v] = w; w = match[v];
if(vis[w] == 1) Q.push(w), vis[w] = 0;
orig[v] = orig[w] = a;
v = par[w];
}
}
bool bfs(int u) {
fill(vis+1, vis+1+N, -1); iota(orig + 1, orig + N + 1, 1);
Q = queue<int> (); Q.push(u); vis[u] = 0;
while(!Q.empty()) {
int v = Q.front(); Q.pop();
for(int x: conn[v]) {
if(vis[x] == -1) {
par[x] = v; vis[x] = 1;
if(!match[x]) return augment(u, x), true;
Q.push(match[x]); vis[match[x]] = 0;
}
else if(vis[x] == 0 && orig[v] != orig[x]) {
int a = lca(orig[v], orig[x]);
blossom(x, v, a); blossom(v, x, a);
}
}
}
return false;
}
int Match() {
int ans = 0;
// find random matching (not necessary, constant improvement)
vector<int> V(N-1); iota(V.begin(), V.end(), 1);
shuffle(V.begin(), V.end(), mt19937(0x94949));
for(auto x: V) if(!match[x]){
for(auto y: conn[x]) if(!match[y]) {
match[x] = y, match[y] = x;
++ans; break;
}
}
for(int i=1; i<=N; ++i) if(!match[i] && bfs(i)) ++ans;
return ans;
}

View File

@@ -0,0 +1,28 @@
vi adj[N];
int in[N], c = 0;
stack<int> p;
bool fin[N]; int scn[N], nscc = 0;
int dfs(int s) {
in[s] = ++c;
p.push(s);
int m = c;
for(auto i : adj[s]) {
if(in[i] == 0) m = min(m, dfs(i));
else if(!fin[i]) m = min(m, in[i]);
}
if(m == in[s]) {
nscc++;
while(p.top() != s)
{
int i = p.top(); p.pop();
scn[i] = nscc; fin[i] = true;
}
p.pop();
scn[s] = nscc; fin[s] = true;
}
return m;
}
forr(i, n) if(!fin[i]) dfs(i);