CSP 2019 模板整合
qwq以下都为9.24后写的模板
ios::sync_with_stdio(false);
namespace IO{
const int S = 1 << 20;
char I[S + 1], *Is = I, *It = I, O[S + 1], *Ot = O;
char gc() {return Is == It ? ((It = (Is = I) + fread(I, 1, S, stdin)) == I ? EOF: *Is++): *Is++;}
void flush() {fwrite(O, 1, Ot - O, stdout), Ot = O;}
void pc(char ch) {Ot == O + S? flush(), *Ot++ =ch: *Ot++ = ch;}
struct flusher{ ~flusher(){flush();}}Flusher;
#define getchar gc
#define putchar pc
inline int read() {
int x = 0; char v = gc();
for (; v < 48 || v > 57; v = gc());
for (; v >= 48 && v <= 57; v = gc()) x = (x << 3) + (x << 1) + (v ^ 48);
return x;
}
inline void write(int x) {
static int buf[100], d;
if (x == 0) pc('0');
else {
for (d = 0; x; x /= 10) buf[++d] = x % 10 + 48;
while (d) pc((char)buf[d--]);
}
}
}
using namespace IO;
线性筛
bool su(int a){
if(a==1)
return 0;
if(a==2||a==3)
return 1;
if(a%6!=1&&a%6!=5)
return 0;
int temp=sqrt(a);
for(int i=5;i<=temp;i+=6)
if(a%i==0||a%(i+2)==0)
return 0;
return 1;
}
快读
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
GCD
int GCD(int x, int y) {
return y ? GCD(y, x % y) : x;
}
快速幂
inline int ksm(int a, int b) {
int ans = 1;
for (; b; b >>= 1, a = 1LL * a * a % Mo)
if (b & 1) ans = 1LL * ans * a % Mo;
return ans;
}
扩欧
void exgcd(int a, int b) {
if (b == 0) {
x = 1, y = 0;
return;
}
exgcd(b, a % b);
int k = x;
x = y, y = k - a / b * y;
}
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
struct Matrix {
int n, a[N][N];
Matrix(int _n = 0) {
n = _n;
memset(a, 0, sizeof(a));
}
void operator ~(){
for (int i = 0; i < n; i++)
a[i][i] = 1;
}
Matrix operator *(const Matrix &b) const {
Matrix sum(n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++)
sum.a[i][k] = (sum.a[i][k] + 1LL * a[i][j] * b.a[j][k] % Mo) % Mo;
return sum;
}
Matrix operator^(long long p) const {
Matrix sum(n), x = *this;
~sum;
for (; p; p >>= 1, x = x * x)
if (p & 1) sum = sum * x;
return sum;
}
} ;
CDQ
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int n, k, b[N], tot, f[N];
struct Node {
int x, y, z, cnt, ans, id;
} a[N], c[N];
inline int read() {
int x = 0, k = 1; char ch = getchar();
for (; ch < 48 || ch > 57; ch = getchar()) k ^= (ch == '-');
for (; ch >= 48 && ch <= 57; ch = getchar()) x = x * 10 + (ch ^ 48);
return k ? x : -x;
}
inline bool cmp (Node x, Node y) {
return x.x == y.x ? x.y == y.y ? x.z < y.z : x.y < y.y : x.x < y.x;
}
inline bool pd_equal(Node x, Node y) {
return x.x != y.x || x.y != y.y || x.z != y.z;
}
inline void add(int x, int val) {
for (; x <= k; x += (x & (-x)))
b[x] += val;
}
inline int query(int x) {
int ans = 0;
for (; x; x -= (x & (-x)))
ans += b[x];
return ans;
}
void CDQ(int l, int r) {
if (l == r)
return;
int mid = l + r >> 1;
CDQ(l, mid), CDQ(mid + 1, r);
for (int i = l, j = mid + 1, k = l; i <= mid || j <= r; k++)
if (j > r || (i <= mid && a[i].y <= a[j].y))
c[k] = a[i++];
else
c[k] = a[j++];
for (int i = l; i <= r; i++)
a[i] = c[i];
for (int i = l; i <= r; i++)
if (a[i].id <= mid)
add(a[i].z, a[i].cnt);
else
a[i].ans += query(a[i].z);
for (int i = l; i <= r; i++)
if (a[i].id <= mid)
add(a[i].z, -a[i].cnt);
}
int main() {
n = read(), k = read();
for (int i = 1; i <= n; i++)
a[i].x = read(), a[i].y = read(), a[i].z = read();
std::sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; i++)
if (!tot || pd_equal(a[i], a[i - 1]))
a[++tot] = a[i], a[tot].id = tot, a[tot].cnt = 1;
else
a[tot].cnt++;
CDQ(1, tot);
for (int i = 1; i <= tot; i++)
f[a[i].ans + a[i].cnt - 1] += a[i].cnt;
for (int i = 0; i < n; i++)
printf("%d\n", f[i]);
return 0;
}
回文自动机(PAM) (9.24)
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
char s[N];
int Len;
struct PAM{
int last, cnt, len[N], fail[N], num[N], k, p, ch[N][26], p1, c[N];
//char s[N];
void init(char *s) {
last = 0, cnt = 1, len[0] = 0, len[1] = -1, fail[0] = 1, fail[1] = 0, s[0] = 26;
}
void insert() {
for (int i = 1; i <= Len; i++) {
s[i] = (s[i] - 97 + k) % 26 + 97;
c[i] = s[i] - 'a';
p = last;
while (s[i - len[p] - 1] != s[i])
p = fail[p];
if (!ch[p][s[i]]) {
len[++cnt] = len[p] + 2, p1 = fail[p];
while (s[i - len[p1] - 1] != s[i])
p1 = fail[p1];
fail[cnt] = ch[p1][s[i]];
num[cnt] = num[fail[cnt]] + 1;
ch[p][s[i]] = cnt;
}
last = ch[p][s[i]];
printf("%d%c", num[last], (i == Len) ? '\n' : ' ');
k = num[last];
}
}
} s1;
int main() {
scanf("%s", s + 1);
Len = strlen(s + 1);
s1.init(s);
s1.insert();
return 0;
}
AC自动机 (9.25)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10, M = 160;
int n;
char s[M][N];
int trie[N][26], tot, endword[N], fail[N];
struct Node {
int num, pos;
} Ans[N];
inline void Init(int x) {
memset(trie[x], 0, sizeof(trie[x]));
fail[x] = endword[x] = 0;
}
inline void Build_Trie(int gg) {
int root = 0, len = strlen(s[gg] + 1);
for (int j = 1; j <= len; j++) {
if (!trie[root][s[gg][j] - 'a'])
trie[root][s[gg][j] - 'a'] = ++tot, Init(tot);
root = trie[root][s[gg][j] - 'a'];
}
endword[root] = gg;
}
inline void Get_Fail() {
queue <int> q;
for (int i = 0; i < 26; i++)
if (trie[0][i]) {
q.push(trie[0][i]);
fail[trie[0][i]] = 0;
}
while (!q.empty()) {
int now = q.front();
q.pop();
for (int i = 0; i < 26; i++)
if (trie[now][i]) {
fail[trie[now][i]] = trie[fail[now]][i];
q.push(trie[now][i]);
}
else {
trie[now][i] = trie[fail[now]][i];
}
}
}
inline int query() {
int len = strlen(s[n + 1] + 1), ans = 0, now = 0;
for (int i = 1; i <= len; i++) {
now = trie[now][s[n + 1][i] - 'a'];
for (int j = now; j; j = fail[j])
Ans[endword[j]].num++;
}
return ans;
}
inline bool cmp(Node x, Node y) {
return x.num > y.num || (x.num == y.num && x.pos < y.pos);
}
int main() {
scanf("%d", &n);
while (n != 0) {
tot = 0;
Init(0);
for (int i = 1; i <= n; i++) {
scanf("%s", s[i] + 1);
Ans[i].num = 0, Ans[i].pos = i;
Build_Trie(i);
}
fail[0] = 0;
Get_Fail();
scanf("%s", s[n + 1] + 1);
query();
std::sort(Ans + 1, Ans + 1 + n, cmp);
printf("%d\n%s\n", Ans[1].num, s[Ans[1].pos] + 1);
for (int i = 2; i <= n; i++)
if (Ans[1].num == Ans[i].num)
printf("%s\n", s[Ans[i].pos] + 1);
else
break;
scanf("%d", &n);
}
return 0;
}
‘’
可持久化线段树(主席树) (9.25)
(静态区间第k小)
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int l[N << 5], r[N << 5], cnt, sum[N << 5], a[N], b[N], c[N], n, q, m;
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline int Build(int t, int w) {
int now = ++cnt, mid = (t + w) >> 1;
sum[now] = 0;
if (t < w) {
l[now] = Build(t, mid);
r[now] = Build(mid + 1, w);
}
return now;
}
inline int add(int k, int t, int w, int x) {
int now = ++cnt, mid = (t + w) >> 1;
l[now] = l[k], r[now] = r[k], sum[now] = sum[k] + 1;
if (t < w && x <= mid)
l[now] = add(l[k], t, mid, x);
else if (t < w && x > mid)
r[now] = add(r[k], mid + 1, w, x);
return now;
}
inline int ask(int L, int R, int t, int w, int x) {
if (t >= w)
return t;
int mid = (t + w) >> 1, k = sum[l[R]] - sum[l[L]];
if (k >= x)
return ask(l[L], l[R], t, mid, x);
else
return ask(r[L], r[R], mid + 1, w, x - k);
}
int main() {
n = read(), q = read();
for (int i = 1; i <= n; i++)
b[i] = a[i] = read();
std::sort(b + 1, b + 1 + n);
m = unique(b + 1, b + 1 + n) - b - 1;
c[0] = Build(1, m);
for (int i = 1; i <= n; i++) {
int now = lower_bound(b + 1, b + 1 + m, a[i]) - b;
c[i] = add(c[i - 1], 1, m, now);
}
for (int i = 1; i <= q; i++) {
int x = read(), y = read(), z = read();
printf("%d\n", b[ask(c[x - 1], c[y], 1, m, z)]);
}
return 0;
}
Manacher (9.25)
#include<bits/stdc++.h>
using namespace std;
const int N = 31000000;
int len, hw[N], ans;
char s[N];
inline void Manacher() {
int maxright = 0, mid = 0;
for (int i = 1; i < len; i++) {
if (i < maxright)
hw[i] = std::min(hw[(mid << 1) - i], hw[mid] + mid - i);
else
hw[i] = 1;
while (s[i + hw[i]] == s[i - hw[i]])
++hw[i];
if (hw[i] + i > maxright)
maxright = hw[i] + i, mid = i;
}
}
int main() {
scanf("%s", s + 1);
len = strlen(s + 1);
for (int i = len; i >= 1; i--)
s[i * 2] = s[i];
s[0] = s[1] = '#';
for (int i = 1; i <= len; i++)
s[i * 2 + 1] = '#';
s[len * 2 + 2] = 0;
len = len * 2 + 2;
Manacher();
ans = 1;
for (int i = 0; i < len; i++)
ans = std::max(ans, hw[i]);
printf("%d\n", ans - 1);
return 0;
}
线性基 (9.26)
插入、判断、查询最大最小值、查询第\(k\)小值
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 110;
const int M = 50;
int n;
long long x, f[N + 10], a[M + 10], b[N + 10], ANS;
bool flag;
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline long long read1() {
long long x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline void Insert(long long x) { //插入
for (int i = M; i >= 0; i--)
if (x & (1ll << i))
if (!a[i]) {
a[i] = x;
return;
}
else x ^= a[i];
flag = true;
}
inline bool check(long long x) { //判断
for (int i = M; i >= 0; i--)
if (x & (1ll << i)) {
if (!a[i])
return false;
else
x ^= a[i];
}
return true;
}
inline long long Ask_max() { //查询最大值
long long maxx = 0;
for (int i = M; i >= 0; i--)
maxx = std::max(maxx, maxx ^ a[i]);
return maxx;
}
inline long long Ask_min() { //查询最小值
if (flag)
return 0;
for (int i = 0; i <= M; i++)
if (a[i])
return a[i];
}
inline long long Ask_kth(long long x) { //查询第k小值
long long ans = 0;
int cnt = 0;
x -= flag;
if (!x)
return 0;
for (int i = 0; i <= M; i++) {
for (int j = i - 1; j >= 0; j--)
if (a[i] & (1ll << j))
a[i] ^= a[j];
if (a[i])
b[cnt++] = a[i];
}
if (x >= (1ll << cnt))
return -1;
for (int i = 0; i < cnt; i++)
if (x & (1ll << i))
ans ^= b[i];
return ans;
}
signed main() {
n = read();
for (int i = 1; i <= n; i++)
f[i] = read1();
std::sort(f + 1, f + 1 + n);
for (int i = 1; i <= n; i++)
if (check(f[i]))
ANS += f[i];
else
Insert(f[i]);
printf("%lld\n", ANS);
return 0;
}
高斯消元 (9.26)
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int n;
double a[N][N];
inline bool Gauss(int n, int m) {
for (int i = 1; i <= n; i++) {
int maxx = i;
for (int j = i + 1; j <= n; j++)
if (fabs(a[j][i]) > fabs(a[maxx][i]))
maxx = j;
for (int j = 1; j <= m; j++)
std::swap(a[i][j], a[maxx][j]);
if (!a[i][i])
return false;
for (int j = 1; j <= n; j++)
if (j != i) {
double t = a[j][i] / a[i][i];
for (int k = i + 1; k <= m; k++)
a[j][k] = a[j][k] - a[i][k] * t;
}
}
return true;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n + 1; j++)
scanf("%lf", &a[i][j]);
if (!Gauss(n, n + 1))
return printf("No Solution\n"), 0;
for (int i = 1; i <= n; i++)
printf("%.2f\n", a[i][n + 1] / a[i][i]);
return 0;
}
矩阵求逆 (9.26)
#include<bits/stdc++.h>
using namespace std;
const int N = 1010, Mo = 1e9 + 7;
int n, a[N][N];
inline int ksm(int a, int b) {
int ans = 1;
for (; b; b >>= 1, a = 1LL * a * a % Mo)
if (b & 1) ans = 1LL * ans * a % Mo;
return ans;
}
inline bool Gauss(int n, int m) {
for (int i = 1; i <= n; i++) {
int maxx = i;
for (int j = i + 1; j <= n; j++)
if (fabs(a[j][i]) > fabs(a[maxx][i]))
maxx = j;
if (i != maxx)
for (int j = 1; j <= m; j++)
std::swap(a[i][j], a[maxx][j]);
if (!a[i][i])
return false;
int d = ksm(a[i][i], Mo - 2);
for (int j = i; j <= m; j++)
a[i][j] = 1LL * a[i][j] * d % Mo;
for (int j = 1; j <= n; j++)
if (j != i) {
d = a[j][i];
for (int k = i; k <= m; k++)
a[j][k] = (a[j][k] - 1LL * a[i][k] * d % Mo + Mo) % Mo;
}
}
return true;
}
signed main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++)
scanf("%d", &a[i][j]);
a[i][n + i] = 1;
}
if (!Gauss(n, n + n))
return printf("No Solution\n"), 0;
for (int i = 1; i <= n; i++)
for (int j = n + 1; j <= n + n; j++)
printf("%d%c", a[i][j], " \n"[j == n + n]);
return 0;
}
普通莫队 (9.27)
#include<bits/stdc++.h>
using namespace std;
const int N = 3e4 + 10, M = 2e6 + 10;
int n, m, now, be[M], a[M], cnt[M], ans[M];
struct Node {
int l, r, id;
} q[M];
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline bool cmp(Node a, Node b) {
return (be[a.l] ^ be[b.l]) ? be[a.l] < be[b.l] : ((be[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
int main() {
n = read();
int sz = sqrt(n), n1 = ceil((double)n / sz);
for (int i = 1; i <= n1; i++)
for (int j = (i - 1) * sz + 1; j <= i * sz; j++)
be[j] = i;
for (int i = 1; i <= n; i++)
a[i] = read();
m = read();
for (int i = 1; i <= m; i++)
q[i].l = read(), q[i].r = read(), q[i].id = i;
std::sort(q + 1, q + 1 + m, cmp);
int L = 1, R = 0;
for (int i = 1; i <= m; i++) {
int l = q[i].l, r = q[i].r;
while (L < l)
now -= !--cnt[a[L++]];
while (L > l)
now += !cnt[a[--L]]++;
while (R < r)
now += !cnt[a[++R]]++;
while (R > r)
now -= !--cnt[a[R--]];
ans[q[i].id] = now;
}
for (int i = 1; i <= m; i++)
printf("%d\n", ans[i]);
return 0;
}
带修莫队 (9.27)
#include<bits/stdc++.h>
using namespace std;
const int N = 3e4 + 10, M = 2e6 + 10;
int n, m, now, be[M], a[M], cnt[M], ans[M], cntc, cntq;
char ch;
struct Query {
int l, r, id, time;
} q[M];
struct Replace {
int pos, color;
} c[M];
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline bool cmp(Query a, Query b) {
return (be[a.l] ^ be[b.l]) ? be[a.l] < be[b.l] : ((be[a.r] ^ be[b.r]) ? be[a.r] < be[b.r] : a.time < b.time);
}
int main() {
n = read(), m = read();
int sz = pow(n, 2.0 / 3.0), n1 = ceil((double)n / sz);
for (int i = 1; i <= n1; i++)
for (int j = (i - 1) * sz + 1; j <= i * sz; j++)
be[j] = i;
for (int i = 1; i <= n; i++)
a[i] = read();
for (int i = 1; i <= m; i++) {
scanf("%c", &ch);
while (ch != 'Q' && ch != 'R')
scanf("%c", &ch);
if (ch == 'Q') {
q[++cntq].l = read(), q[cntq].r = read(), q[cntq].time = cntc, q[cntq].id = cntq;
}
else if (ch == 'R') {
c[++cntc].pos = read(), c[cntc].color = read();
}
}
std::sort(q + 1, q + 1 + cntq, cmp);
int L = 1, R = 0, Time = 0;
for (int i = 1; i <= m; i++) {
int l = q[i].l, r = q[i].r, time = q[i].time;
while (L < l)
now -= !--cnt[a[L++]];
while (L > l)
now += !cnt[a[--L]]++;
while (R < r)
now += !cnt[a[++R]]++;
while (R > r)
now -= !--cnt[a[R--]];
while (Time < time) {
Time++;
if (l <= c[Time].pos && r >= c[Time].pos)
now -= !--cnt[a[c[Time].pos]] - !cnt[c[Time].color]++;
std::swap(a[c[Time].pos], c[Time].color);
}
while (Time > time) {
if (l <= c[Time].pos && r >= c[Time].pos)
now -= !--cnt[a[c[Time].pos]] - !cnt[c[Time].color]++;
std::swap(a[c[Time].pos], c[Time].color);
Time--;
}
ans[q[i].id] = now;
}
for (int i = 1; i <= cntq; i++)
printf("%d\n", ans[i]);
return 0;
}
折半搜索 (9.30)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10, M = 1 << 21;
int n;
long long aa[N], m;
long long suma[M], sumb[M], cnta, cntb;
long long ans;
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline long long read1() {
long long x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
void dfs(int l, int r, long long sum, long long a[], long long &cnt) {
if (sum > m)
return;
if (l > r) {
a[++cnt] = sum;
return;
}
dfs(l + 1, r, sum + aa[l], a, cnt);
dfs(l + 1, r, sum, a, cnt);
}
signed main() {
n = read(), m = read1();
for (int i = 1; i <= n; i++)
aa[i] = read1();
dfs(1, n >> 1, 0, suma, cnta);
dfs((n >> 1) + 1, n, 0, sumb, cntb);
std::sort(suma + 1, suma + 1 + cnta);
for (int i = 1; i <= cntb; i++)
ans += upper_bound(suma + 1, suma + 1 +cnta, m - sumb[i]) - suma - 1;
printf("%lld", ans);
return 0;
}
树链剖分 (9.30)
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, M = N << 2;
int n, m, r, Mo, num, from[N], nxt[N], to[N], w[N], w1[N], a[M], lazy[M];
int son[N], id[N], father[N], depth[N], size[N], top[N], cnt, res;
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline void add(int x, int y) { // build tree
to[++num] = y, nxt[num] = from[x], from[x] = num;
}
void dfs1(int x, int fa, int deep) {
depth[x] = deep, father[x] = fa, size[x] = 1;
int maxx = -1; // find height son
for (int i = from[x]; i; i = nxt[i]) {
int y = to[i];
if (y == fa) // father
continue;
dfs1(y, x, deep + 1);
size[x] += size[y];
if (size[y] > maxx)
son[x] = y, maxx = size[y];
}
}
void dfs2(int x, int Top) { // link top
id[x] = ++cnt; // new number
w1[cnt] = w[x]; // new value
top[x] = Top;
if (!son[x]) return; //no sum
dfs2(son[x], Top);
for (int i = from[x]; i; i = nxt[i]) {
int y = to[i];
if (y == father[x] || y == son[x]) // father or height son
continue;
dfs2(y, y); // light son -> link top
}
}
/*********Segment Tree***********/
inline void pushdown(int x, int y) {
int l = x << 1, r = x << 1 | 1;
lazy[l] += lazy[x], lazy[r] += lazy[x];
a[l] = (a[l] + lazy[x] * (y - (y >> 1))) % Mo;
a[r] = (a[r] + lazy[x] * (y >> 1)) % Mo;
lazy[x] = 0;
}
void build(int x, int l, int r) {
if (l == r) {
a[x] = w1[l] % Mo;
return;
}
build(x << 1, l, l + r >> 1);
build(x << 1 | 1, (l + r >> 1) + 1, r);
a[x] = (a[x << 1] + a[x << 1 | 1]) % Mo;
}
void query(int x, int l, int r, int L, int R) {
if (L <= l && R >= r) {
res = (res + a[x]) % Mo;
return;
}
if (lazy[x])
pushdown(x, r - l + 1);
if (L <= (l + r >> 1))
query(x << 1, l, l + r >> 1, L, R);
if (R > (l + r >> 1))
query(x << 1 | 1, (l + r >> 1) + 1, r, L, R);
}
void update(int x, int l, int r, int L, int R, int k) {
if (L <= l && R >= r) {
lazy[x] += k, a[x] += k * (r - l + 1);
return;
}
if (lazy[x]) pushdown(x, r - l + 1);
if (L <= (l + r >> 1))
update(x << 1, l, l + r >> 1, L, R, k);
if (R > (l + r >> 1))
update(x << 1 | 1, (l + r >> 1) + 1, r, L, R, k);
a[x] = (a[x << 1] + a[x << 1 | 1]) % Mo;
}
/*********Segment Tree***********/
inline void addroad(int x, int y, int k) {
k %= Mo;
while (top[x] != top[y]) { // not same link
if (depth[top[x]] < depth[top[y]])
std::swap(x, y);
update(1, 1, n, id[top[x]], id[x], k);
x = father[top[x]];
}
if (depth[x] > depth[y])
std::swap(x, y);
update(1, 1, n, id[x], id[y], k);
}
inline int sumroad(int x, int y) {
int ans = 0;
while (top[x] != top[y]) {
if (depth[top[x]] < depth[top[y]])
std::swap(x, y);
res = 0;
query(1, 1, n, id[top[x]], id[x]);
ans = (ans + res) % Mo;
x = father[top[x]];
}
if (depth[x] > depth[y])
std::swap(x, y);
res = 0;
query(1, 1, n, id[x], id[y]);
return (ans + res) % Mo;
}
inline int sumson(int x) {
res = 0;
query(1, 1, n, id[x], id[x] + size[x] - 1);
return res;
}
inline void addson(int x, int k) {
update(1, 1, n, id[x], id[x] + size[x] - 1, k);
}
int main() {
n = read(), m = read(), r = read(), Mo = read();
for (int i = 1; i <= n; i++)
w[i] = read();
for (int i = 1; i < n; i++) {
int x = read(), y = read();
add(x, y), add(y, x);
}
dfs1(r, 0, 1);
dfs2(r, r);
build(1, 1, n);
while (m--) {
int opt = read(), x = read();
if (opt == 1) {
int y = read(), z = read();
addroad(x, y, z); // (x - y) path -> add z
}
else if (opt == 2) {
int y = read();
printf("%d\n", sumroad(x, y)); // (x - y) path -> sum
}
else if (opt == 3) {
int y = read();
addson(x, y); // subtree -> add z
}
else if (opt == 4)
printf("%d\n", sumson(x)); // subtree -> sum
}
return 0;
}
匈牙利算法 (10.2)
#include<bits/stdc++.h>
using namespace std;
const int N = 2010;
int n, m, e, Match[N << 1], ans, ask[N << 1], head[N], cnt;
struct Node {
int to, nxt;
} edge[N * N];
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline void add(int u, int v) {
edge[++cnt] = (Node) {v, head[u]}, head[u] = cnt;
}
inline bool found(int x) {
for (int i = head[x]; i; i = edge[i].nxt) {
int y = edge[i].to;
if (ask[y]) continue;
ask[y] = 1;
if (!Match[y] || found(Match[y])) {
Match[y] = x;
return true;
}
}
return false;
}
inline void match() {
for (int i = 1; i <= n; i++) {
memset(ask, 0, sizeof(ask));
if (found(i))
ans++;
}
}
int main() {
n = read(), m = read(), e = read();
for (int i = 1; i <= e; i++) {
int u = read(), v = read();
if (v > m || u > n)
continue;
add(u, v + n);
}
match();
printf("%d\n", ans);
return 0;
}
Hopcroft-Karp (未)
//不是我的代码
/*
dx[i]表示左集合i顶点的距离编号
dy[i]表示右集合i顶点的距离编号
mx[i]表示左集合顶点所匹配的右集合顶点序号
my[i]表示右集合i顶点匹配到的左集合顶点序号
*/
#include <bits/stdc++.h>
#define N 1005
#define M 1000005
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[25];int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
struct node{
int to,next;
}e[M];
int head[N],tot=0;
inline void add(register int u,register int v)
{
e[++tot]=(node){v,head[u]};
head[u]=tot;
}
int n,m,es,ans;
int dx[N],dy[N],mx[N],my[N],vis[N],dis;
inline bool bfs()
{
queue<int> q;
dis=1926081700;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(register int i=1;i<=n;++i)
if(mx[i]==-1)
{
q.push(i);
dx[i]=0;
}
while(!q.empty())
{
int u=q.front();
q.pop();
if(dx[u]>dis)
break;
for(register int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(dy[v]==-1)
{
dy[v]=dx[u]+1;
if(my[v]==-1)
dis=dy[v];
else
{
dx[my[v]]=dy[v]+1;
q.push(my[v]);
}
}
}
}
return dis!=1926081700;
}
inline bool dfs(register int u)
{
for(register int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(vis[v]||(dy[v]!=dx[u]+1))
continue;
vis[v]=1;
if(my[v]!=-1&&dy[v]==dis)
continue;
if(my[v]==-1||dfs(my[v]))
{
my[v]=u;
mx[u]=v;
return true;
}
}
return false;
}
inline void match()
{
memset(mx,-1,sizeof(mx));
memset(my,-1,sizeof(my));
while(bfs())
{
memset(vis,0,sizeof(vis));
for(register int i=1;i<=n;++i)
if(mx[i]==-1&&dfs(i))
++ans;
}
}
int main()
{
n=read(),m=read(),es=read();
while(es--)
{
int u=read(),v=read();
if(v>m)
continue;
add(u,v);
}
match();
write(ans);
return 0;
}
Kuhn-Munkras (10.5)
#include<bits/stdc++.h>
using namespace std;
const int N = 110, INF = 0x3f3f3f3f;
bool tfg[N], tfb[N];
int b[N], g[N], a[N][N], match[N], slack[N], n;
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
bool pd(int x) {
tfg[x] = true;
for (int i = 1; i <= n; i++) {
if (tfb[i])
continue;
int t = b[i] + g[x] - a[x][i];
if (t == 0) {
tfb[i] = true;
if (match[i] == -1 || pd(match[i])) {
match[i] = x;
return true;
}
}
else
slack[i] = std::min(slack[i], t);
}
return false;
}
inline void KM() {
memset(match, -1, sizeof(match));
memset(b, 0, sizeof(b));
for (int i = 1; i <= n; i++) {
g[i] = a[i][1];
for (int j = 2; j <= n; j++)
g[i] = std::max(g[i], a[i][j]);
}
for (int i = 1; i <= n; i++) {
fill(slack + 1, slack + n + 1, INF);
while (true) {
memset(tfb, false, sizeof(tfb));
memset(tfg, false, sizeof(tfg));
if (pd(i))
break;
int d = INF;
for (int j = 1; j <= n; j++)
if (!tfb[j])
d = std::min(d, slack[j]);
for (int j = 1; j <= n; j++) {
if (tfg[j])
g[j] -= d;
if (tfb[j]) b[j] += d; else slack[j] -= d;
}
}
}
}
int main() {
n = read();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
a[i][j] = read();
KM();
int ans = 0;
for (int i = 1; i <= n; i++)
ans += a[match[i]][i];
printf("%d\n", ans);
return 0;
}
动态dp (10.7)
#include<bits/stdc++.h>
using namespace std;
const int INF = -0x3f, N = 1e5 + 10, M = 4e5 + 10;
int n, m, cnt, head[N], to[M], nxt[M], siz[N], fa[N], val[N], son[N], cnt1, id[N], dfn[N], End[N], top1[N], f[N][2], L[N << 2], R[N << 2];
struct Matrix {
int mat[2][2];
Matrix() {
memset(mat, INF, sizeof(mat));
}
inline Matrix operator * (Matrix b) {
Matrix a;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
a.mat[i][j] = std::max(a.mat[i][j], mat[i][k] + b.mat[k][j]);
return a;
}
} Val[N << 2], a[N << 2];
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline void add(int x, int y) {
to[++cnt] = y, nxt[cnt] = head[x], head[x] = cnt;
}
void dfs1(int x) {
siz[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
int y = to[i];
if (y == fa[x])
continue;
fa[y] = x;
dfs1(y);
siz[x] += siz[y];
if (siz[y] > siz[son[x]]) // height son
son[x] = y;
}
}
void dfs2(int x, int Top) {
id[x] = ++cnt1, dfn[cnt1] = x, top1[x] = Top, End[Top] = std::max(End[Top], cnt1);
f[x][0] = 0, f[x][1] = val[x];
Val[x].mat[0][0] = Val[x].mat[0][1] = 0, Val[x].mat[1][0] = val[x];
if (son[x] != 0) {
dfs2(son[x], Top);
f[x][0] += std::max(f[son[x]][0], f[son[x]][1]);
f[x][1] += f[son[x]][0];
}
for (int i = head[x]; i; i = nxt[i]) {
int y = to[i];
if (y== fa[x] || y == son[x])
continue;
dfs2(y, y);
f[x][0] += std::max(f[y][0], f[y][1]), f[x][1] += f[y][0];
Val[x].mat[0][0] += std::max(f[y][0], f[y][1]);
Val[x].mat[0][1] = Val[x].mat[0][0], Val[x].mat[1][0] += f[y][0];
}
}
void Build(int l, int r, int x) {
L[x] = l, R[x] = r;
if (L[x] == R[x]) {
a[x] = Val[dfn[L[x]]];
return;
}
Build(L[x], L[x] + R[x] >> 1, x << 1);
Build((L[x] + R[x] >> 1) + 1, R[x], x << 1 | 1);
a[x] = a[x << 1] * a[x << 1 | 1];
}
void update(int x, int i) {
if (L[i] == R[i]) {
a[i] = Val[dfn[x]];
return;
}
if (x <= (L[i] + R[i] >> 1))
update(x, i << 1);
else
update(x, i << 1 | 1);
// update(x, (x <= (L[i] + R[i] >> 1)) ? (i << 1) : (i << 1 | 1));
a[i] = a[i << 1] * a[i << 1 | 1];
}
Matrix query(int l, int r, int x) {
if (L[x] == l && R[x] == r)
return a[x];
int mid = L[x] + R[x] >> 1;
if (r <= mid) return query(l, r, x << 1);
else if (l > mid) return query(l, r, x << 1 | 1);
else return query(l, mid, x << 1) * query(mid + 1, r, x << 1 | 1);
}
void update_path(int x, int y) {
Val[x].mat[1][0] += y - val[x], val[x] = y;
Matrix a, b;
while (x != 0) {
a = query(id[top1[x]], End[top1[x]], 1);
update(id[x], 1);
b = query(id[top1[x]], End[top1[x]], 1), x = fa[top1[x]];
Val[x].mat[0][0] += std::max(b.mat[0][0], b.mat[1][0]) - std::max(a.mat[0][0], a.mat[1][0]), Val[x].mat[0][1] = Val[x].mat[0][0];
Val[x].mat[1][0] += b.mat[0][0] - a.mat[0][0];
}
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++)
val[i] = read();
for (int i = 1; i < n; i++) {
int x = read(), y = read();
add(x, y), add(y, x);
}
dfs1(1);
dfs2(1, 1);
Build(1, n, 1);
for (int i = 1; i <= m; i++) {
int x = read(), y = read();
update_path(x, y);
Matrix ans = query(id[1], End[1], 1);
printf("%d\n", std::max(ans.mat[0][0], ans.mat[1][0]));
}
return 0;
}
缩点(10.8)
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, color[N];
vector<int> a[N];
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
pair<int, int> dfs(int x, int fa, int depth) {
int sz = a[x].size();
pair<int, int> tmp = make_pair(depth, x);
for (int i = 0; i < sz; i++) {
int y = a[x][i];
if (y == fa)
continue;
if(color[y] != color[x])
tmp = std::max(tmp, dfs(y, x, depth + 1));
else
tmp = std::max(tmp, dfs(y, x, depth));
}
return tmp;
}
int main() {
n = read();
for (int i = 1; i <= n; i++)
color[i] = read();
for (int i = 1; i < n; i++) {
int x = read(), y = read();
a[x].push_back(y), a[y].push_back(x);
}
pair<int, int> tmp = dfs(1, -1, 0);
tmp = dfs(tmp.second, -1, 0);
printf("%d\n", tmp.first + 1 >> 1);
}
Lucas (10.9)
inline long long ksm(long long a, long long b) {
long long ans = 1;
a = a % Mo;
for (; b; b >>= 1, a = a * a % Mo)
if (b & 1) ans = ans * a % Mo;
return ans;
}
inline long long C(long long n, long long m) {
if (m > n) return 0;
long long a = 1, b = 1;
for (long long i = 1; i <= m; i++)
a = a * (n + i - m) % Mo, b = b * i % Mo;
return a * ksm(b, Mo - 2) % Mo;
}
inline long long Lucas(long long n, long long m) {
long long ans = 1;
for (; n && m; n /= Mo, m /= Mo)
ans = ans * C(n % Mo, m % Mo);
return ans;
}
Simpson 1(10.9)
#include<bits/stdc++.h>
using namespace std;
const double Eps = 1e-6;
double a, b, c, d, L, R;
inline double f(double x) {
return (c * x + d) / (a * x + b);
}
inline double Simpson(double L, double R) {
double mid = (L + R) / 2;
return ((R - L) * (f(L) + f(R) + 4 * f(mid))) / 6.0;
}
inline double Solve(double L, double R, double eps, double ans) {
double mid = (L + R) / 2;
double l = Simpson(L, mid), r = Simpson(mid, R);
if (fabs(l + r - ans) <= eps * 15)
return l + r + (l + r - ans) / 15;
return Solve(L, mid, eps / 2, l) + Solve(mid, R, eps / 2, r);
}
inline double Solve(double L, double R, double eps) {
return Solve(L, R, eps, Simpson(L, R));
}
int main() {
scanf("%lf%lf%lf%lf%lf%lf", &a, &b, &c, &d, &L, &R);
printf("%.6f", Solve(L, R, Eps));
return 0;
}
Simpson 2 (10.10)
#include<bits/stdc++.h>
using namespace std;
const double Eps = 1e-8;
double a, b, c, d, L, R;
inline double f(double x) {
return pow(x, a / x - x);
}
inline double Simpson(double L, double R) {
double mid = (L + R) / 2;
return ((R - L) * (f(L) + f(R) + 4 * f(mid))) / 6.0;
}
inline double Solve(double L, double R, double eps, double ans) {
double mid = (L + R) / 2;
double l = Simpson(L, mid), r = Simpson(mid, R);
if (fabs(l + r - ans) <= eps * 15)
return l + r + (l + r - ans) / 15;
return Solve(L, mid, eps / 2, l) + Solve(mid, R, eps / 2, r);
}
inline double Solve(double a, double b) {
return Solve(a, b, Eps, Simpson(a, b));
}
int main() {
scanf("%lf", &a);
if (a < 0)
return puts("orz"), 0;
printf("%.5f", Solve(Eps, 20.0));
return 0;
}
\(\mathcal{01trie}\)
#include<bits/stdc++.h>
#define pow(x, i) (x >> i)
using namespace std;
const int N = 6e6 + 10, M = 30;
int cnt[N], trie[N][2], tot = 1, n;
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline void add(int x, int dg) {
int p = 1;
for (int i = M; i >= 0; --i) {
if (dg == 1) trie[p][(pow(x, i) & 1)] = (trie[p][(pow(x, i) & 1)] != 0) ? trie[p][(pow(x, i) & 1)] : (++tot);
p = trie[p][(pow(x, i) & 1)], cnt[p] += dg;
}
}
inline int ask(int x, int y) {
int p = 1;
int sum = 0;
for (int i = M; i >= 0; i--) {
int t = (pow(y, i) & 1), t1 = (pow(x, i) & 1);
if (t)
sum += cnt[trie[p][t1]], p = trie[p][t1 ^ 1];
else
p = trie[p][t1];
}
return sum;
}
int main() {
n = read();
while (n--) {
int opt = read(), x = read();
if (opt == 1)
add(x, 1);
else if (opt == 2)
add(x, -1);
else if (opt == 3) {
int y = read();
printf("%d\n", ask(x, y));
}
}
return 0;
}
树的重心
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
struct Node {
int to, nxt;
} edge[N << 1];
int cnt, n, m, Fa[N], sz[N], ans[N], head[N];
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
inline void Build(int x, int y) {
edge[++cnt].to = x, edge[cnt].nxt = head[y], head[y] = cnt;
}
void dfs(int x, int fa) {
int res = 0;
sz[x] = 1, ans[x] = x;
for (int i = head[x]; i; i = edge[i].nxt) {
int y = edge[i].to;
if (y == fa)
continue;
dfs(y, x);
sz[x] += sz[y], res = (sz[y] > sz[res]) ? y : res;
}
if ((sz[res] << 1) > sz[x])
for (ans[x] = ans[res]; ((sz[x] - sz[ans[x]]) << 1) > sz[x]; ans[x] = Fa[ans[x]]);
}
int main() {
n = read(), m = read();
for (int i = 2; i <= n; i++) {
Fa[i] = read();
Build(i, Fa[i]);
Build(Fa[i], i);
}
dfs(1, 0);
while (m--) {
int x = read();
printf("%d\n", ans[x]);
}
return 0;
}
二分图多重匹配(未)
2-SAT
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
const int N = 1e6;
int n, m, num, cnt, NUM, u1, v1, u2, v2, dfn[N << 2], low[N << 2], Stack[N << 2], f[N << 2], head[N << 2], a, x, b, y, tot;
bool vis[N << 2];
struct Node {
int to, nxt, from;
} edge[N << 2];
inline int read() {
int x = 0, k = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) k ^= (c == '-');
for (; c >= 48 && c <= 57; c = getchar()) x = x * 10 + (c ^ 48);
return k ? x : -x;
}
void Tarjan(int x, int fa) {
dfn[x] = low[x] = ++num, vis[x] = true, Stack[++cnt] = x;
bool tf = 0;
for (int i = head[x]; i; i = edge[i].nxt) {
int y = edge[i].to;
if (y == fa && !tf) {
tf = 1;
continue;
}
if (!dfn[y]) {
Tarjan(y, x);
low[x] = std::min(low[x], low[y]);
}
else if (!f[y]) {
low[x] = std::min(low[x], dfn[y]);
}
}
if (dfn[x] == low[x]) {
NUM++;
for (; Stack[cnt] != x; ) f[Stack[cnt]] = NUM, vis[Stack[cnt]] = 0, --cnt;
f[Stack[cnt]] = NUM, vis[Stack[cnt]] = 0;
cnt--;
}
}
inline void add(int x, int y) {
edge[++tot].to = y, edge[tot].from = x, edge[tot].nxt = head[x], head[x] = tot;
}
int main() {
n = read(), m = read();
for (int i = 1; i <= m; i++) {
a = read(), x = read(), b = read(), y = read();
if (x == 0)
u1 = a + n, v2 = a;
else if (x == 1)
u1 = a, v2 = a + n;
if (y == 0)
v1 = b, u2 = b + n;
else if (y == 1)
v1 = b + n, u2 = b;
add(u1, v1), add(u2, v2);
}
for (int i = 1; i <= 2 * n; i++)
if (!dfn[i])
Tarjan(i, 0);
for (int i = 1; i <= n; i++)
if (f[i] == f[i + n]) {
printf("IMPOSSIBLE\n");
return 0;
}
printf("POSSIBLE\n");
for (int i = 1; i <= n; i++)
printf("%d ", f[i] > f[i + n] ? 1 : 0);
return 0;
}
dij + Tarjan + 拓扑
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 10, INF = 1e16 + 10;
int In[N], dis[N], dis1[N], cnt, cnt1, head[N], head1[N], dfn[N], f[N], sum, Stack[N], low[N], n, m, ans[N], num;
bool vis[N];
struct node {
int to, nxt, e, p, from;
bool tf;
} E[N], E1[N];
struct Node {
int e, y;
bool operator <(const Node &x) const {
return e > x.e;
}
} ;
inline int read() {
int x = 0, k = 1; char ch = getchar();
for (; ch < 48 || ch > 57; ch = getchar()) k ^= (ch == '-');
for (; ch >= 48 && ch <= 57; ch = getchar()) x = x * 10 + (ch ^ 48);
return k ? x : -x;
}
inline void Build(int x, int y, int e, int p) {
E[++cnt].to = y, E[cnt].from = x, E[cnt].nxt = head[x], head[x] = cnt, E[cnt].e = e, E[cnt].p = p, E[cnt].tf = true;
}
inline void Build1(int x, int y, int e, int p) {
E1[++cnt1].to = x, E1[cnt1].from = y, E1[cnt1].nxt = head1[y], head1[y] = cnt1, E1[cnt1].e = e, E1[cnt1].p = p, E1[cnt1].tf = true;
}
inline void Build2(int from, int to, int p) {
E1[++cnt1].to = to, E1[cnt1].from = from, E1[cnt1].nxt = head1[from], head1[from] = cnt1, E1[cnt1].p = p;
}
priority_queue<Node> q;
void Tarjan(int x) {
dfn[x] = low[x] = ++num, Stack[++sum] = x;
for (int i = head[x]; i; i = E[i].nxt)
if (E[i].tf) {
int y = E[i].to;
if (!dfn[y]) {
Tarjan(y);
low[x] = min(low[x], low[y]);
}
else if (!f[y]) {
low[x] = min(low[x], dfn[y]);
}
}
if (dfn[x] == low[x]) {
for (f[x] = x; Stack[sum] != x; ) {
// E[head[x]].p += E[head[Stack[sum]]].p;
f[Stack[sum]] = x;
sum = sum - 1;
}
sum = sum - 1;
}
}
inline int Topology() {
queue<int> q;
memset(ans, -0x3f, sizeof(ans));
ans[f[1]] = 0;
for (int i = 1; i <= n; i++)
if (!In[i]) {
q.push(i);
}
for (; !q.empty(); ) {
int now = q.front();
q.pop();
for (int i = head1[now]; i; i = E1[i].nxt) {
int y = E1[i].to;
ans[y] = max(ans[y], ans[now] + E1[i].p);
In[y] = In[y] - 1;
if (!In[y]) {
q.push(y);
}
}
}
return ans[f[n]];
}
signed main() {
for (int T = read(); T--; ) {
n = read(), m = read();
num = 0, sum = 0, cnt1 = 0, cnt = 0;
memset(f, 0, sizeof(f));
memset(ans, 0, sizeof(ans));
memset(head, 0, sizeof(head));
memset(head1, 0, sizeof(head1));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(Stack, 0, sizeof(Stack));
for (int i = 1; i <= n; i++)
vis[i] = false;
for (int i = 1; i <= m; i++) {
int x = read(), y = read(), e = read(), p = read();
Build(x, y, e, p);
Build1(x, y, e, p);
}
dis[1] = 0;
for (int i = 2; i <= n; i++)
dis[i] = INF;
for (; !q.empty(); q.pop());
for (q.push((Node) {0, 1}); !q.empty(); ) {
Node now = q.top();
q.pop();
if (vis[now.y]) continue;
vis[now.y] = true;
for (int i = head[now.y]; i; i = E[i].nxt) {
if (dis[E[i].to] > dis[now.y] + E[i].e) {
dis[E[i].to] = dis[now.y] + E[i].e;
q.push((Node) {dis[E[i].to], E[i].to});
}
}
}
dis1[n] = 0, vis[n] = false;
for (int i = 1; i < n; i++)
dis1[i] = INF, vis[i] = 0;
for (; !q.empty(); q.pop());
for (q.push((Node) {0, n}); !q.empty(); ) {
Node now = q.top();
q.pop();
if (vis[now.y]) continue;
vis[now.y] = true;
for (int i = head1[now.y]; i; i = E1[i].nxt) {
if (dis1[E1[i].to] > dis1[now.y] + E1[i].e) {
dis1[E1[i].to] = dis1[now.y] + E1[i].e;
q.push((Node) {dis1[E1[i].to], E1[i].to});
}
}
}
// for (int i = 1; i <= n; i++)
// // printf("%d %d %d\n", i, dis[i], dis1[i]);
// memset(dfn, 0, sizeof(dfn));
for (int i = 1; i <= m; i++)
if (dis[E[i].from] + dis1[E[i].to] + E[i].e != dis[n])
E[i].tf = false, E[i].p = 0;
for (int i = 1; i <= n; i++)
if (!dfn[i])
Tarjan(i);
cnt1 = 0;
memset(In, 0, sizeof(In));
memset(head1, 0, sizeof(head1));
for (int i = 1; i <= m; i++)
if (f[E[i].from] != f[E[i].to] && E[i].tf) {
Build2(f[E[i].from], f[E[i].to], E[i].p);
In[f[E[i].to]]++;
}
printf("%lld %lld\n", dis[n], Topology());
// printf("fsfs");
}
}