又是自闭的一天
T1 首都(capital)
换根dp
首先以1为根搜出所有的反边
然后dp
\(dp\) 到 \(i\) 时,\(i\) 的父亲已经知道答案
只需考虑 \((fa,i)\) 这条边
正为 \(+1\),反为 \(-1\)
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
const int N = 200010 ;
int n, ans ;
int val[N], res[N] ;
vector <pair<int, int> > e[N] ;
void dfs1(int u, int ft) {
rep(i, 0, siz(e[u]) - 1) {
int v = e[u][i].fi ;
if (v == ft) continue ;
dfs1(v, u) ;
val[u] += val[v] + e[u][i].se ;
}
}
void dfs2(int u, int ft, int v1, int v2) {
res[u] = val[1] - v1 + v2 ;
ans = min(ans, res[u]) ;
rep(i, 0, siz(e[u]) - 1) {
int v = e[u][i].fi ;
if (v == ft) continue ;
if (e[u][i].se) dfs2(v, u, v1 + 1, v2) ;
else dfs2(v, u, v1, v2 + 1) ;
}
}
signed main() {
scanf("%d", &n) ;
rep(i, 1, n - 1) {
int u, v ; scanf("%d%d", &u, &v) ;
e[u].pb(mp(v, 0)) ;
e[v].pb(mp(u, 1)) ;
}
ans = 2 * n ;
dfs1(1, 0) ;
dfs2(1, 0, 0, 0) ;
printf("%d\n", ans) ;
rep(i, 1, n) if (res[i] == ans) printf("%d ", i) ;
return 0 ;
}
T2 maxmin
这个题有点意思
题意是查所有子区间 \([i,j](i<j)\) 中最大值-最小值 在 \([l,r]\) 范围内的个数
\(n*q<=2*10^6\) 提示我们是 \(O(nq)\) 的
首先预处理 \((l,r)\) 的区间中最小值和最大值
在 \([l,r]\) 的个数 = 在 \([0,r]\) 的个数-在 \([0,l-1]\) 的个数
然后考虑 \(two-pointers\)
对于一个 \(l\) 我们求出他最大的满足的 \(r\)
算两次
就可以了
其实可以用单调队列,有点类似滑动窗口
可以AC
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
const int N = 500010 ;
int n, q ;
int mx[N][25], mi[N][25], a[N], ans1[N], ans2[N] ;
void build() {
rep(i, 1, n) mx[i][0] = mi[i][0] = a[i] ;
rep(j, 1, 20)
rep(i, 1, n - (1 <<j) + 1) {
mx[i][j] = max(mx[i][j - 1], mx[i + (1 << (j - 1))][j - 1]) ;
mi[i][j] = min(mi[i][j - 1], mi[i + (1 << (j - 1))][j - 1]) ;
}
}
int query(int x, int y) {
if (x > y) swap(x, y) ;
int k = (double) log(y - x + 1) / log(2.0) ;
return max(mx[x][k], mx[y - (1 << k) + 1][k]) - min(mi[x][k], mi[y - (1 << k) + 1][k]) ;
}
ll solve(int L, int R) {
ll ans = 0 ;
for (int i = 1, r = 1; i <= n; i++) {
while (r + 1 <= n && query(i, r + 1) < L) r++ ;
ans1[i] = r ;
}
for (int i = 1, r = 1; i <= n; i++) {
while (r + 1 <= n && query(i, r + 1) <= R) r++ ;
ans2[i] = r ;
}
rep(i, 1, n) if (ans1[i] <= ans2[i]) ans += ans2[i] - ans1[i] ;
return ans ;
}
signed main() {
scanf("%d%d", &n, &q) ;
rep(i, 1, n) scanf("%d", &a[i]) ;
build() ;
while (q--) {
int l, r ; scanf("%d%d", &l, &r) ;
printf("%lld\n", solve(l, r)) ;
}
return 0 ;
}
T3 简单数论题(number)
出题人你有毒吧
直接放板子题,然后 \(n\) 搞 \(10^18\)
代码就不放了