又是自闭的一天
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
", 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
", solve(l, r)) ;
}
return 0 ;
}
T3 简单数论题(number)
出题人你有毒吧
直接放板子题,然后 (n) 搞 (10^18)
代码就不放了