省选貌似已经定在了 5 月 31 日,WC 貌似已经流水。感觉少经历了一次WC有点可惜。
不过现在来看 THUWC2020 是真的逃过一劫。还好没有真的在 2020 年举办。
加油吧。
codeforces - 528C:(本题的难点在于理解题意)要求定向后每个点出度和入度都为偶数,只需要满足(1)定向前每个点度数为偶数(2)整张图有偶数条边。前一个条件直接把奇点两两相连,后一个条件随便找个点连个自环。然后求出 dfs 树从下往上调整。注意处理自环重边。
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 100000;
const int MAXM = 300000;
struct edge{
int to; edge *nxt, *rev;
}edges[2*MAXM + 5], *adj[MAXN + 5], *ecnt = edges;
void addedge(int u, int v) {
if( u != v ) {
edge *p = (++ecnt), *q = (++ecnt);
p->to = v, p->nxt = adj[u], adj[u] = p;
q->to = u, q->nxt = adj[v], adj[v] = q;
p->rev = q, q->rev = p;
}
else {
edge *p = (++ecnt);
p->to = v, p->nxt = adj[u], adj[u] = p;
}
}
int dfn[MAXM + 5], dcnt;
vector<pair<int, int> >ans;
int dfs(int x, edge *f) {
int cnt = 0; dfn[x] = (++dcnt);
for(edge *p=adj[x];p;p=p->nxt) {
if( p == f ) continue;
if( !dfn[p->to] ) {
if( dfs(p->to, p->rev))
ans.push_back(make_pair(x, p->to));
else ans.push_back(make_pair(p->to, x)), cnt ^= 1;
}
else if( dfn[p->to] <= dfn[x] )
ans.push_back(make_pair(p->to, x)), cnt ^= 1;
}
return cnt;
}
int deg[MAXN + 5];
int main() {
int n, m; scanf("%d%d", &n, &m);
for(int i=1;i<=m;i++) {
int a, b; scanf("%d%d", &a, &b);
deg[a]++, deg[b]++, addedge(a, b);
}
int lst = 0;
for(int i=1;i<=n;i++) {
if( deg[i] & 1 ) {
if( lst == 0 ) lst = i;
else addedge(lst, i), lst = 0;
}
}
if( dfs(1, NULL) ) ans.push_back(make_pair(1, 1));
printf("%d
", ans.size());
for(int i=0;i<ans.size();i++)
printf("%d %d
", ans[i].first, ans[i].second);
}
atcoder - AGC029E:记 mx[x] 表示 x 到 1(除了 x)的最大点,再记 f(x, k) 表示从 x 出发经过 <= k(除了 x)的点的点数。则 ans[x] = ans[mx[x]] + f(x, mx[x] - 1),即我们一旦走过 mx[x] 就不会回头。但是这样算 f(mx[x], mx[mx[x]] - 1) 可能会算重。因此如果算重了,需要再减去 f(x 到 mx[x] 的路径上距离 mx[x] 最近的点, mx[mx[x]] - 1)。f 并查集离线算。
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 200000;
vector<int>G[MAXN + 5], q1[MAXN + 5], q2[MAXN + 5];
void addedge(int u, int v) {
G[u].push_back(v), G[v].push_back(u);
}
int mx[MAXN + 5], pos[MAXN + 5];
void dfs1(int x, int f, int m, int p) {
mx[x] = m, pos[x] = p;
if( x > m ) {
for(int i=0;i<G[x].size();i++)
if( G[x][i] != f ) dfs1(G[x][i], x, x, G[x][i]);
}
else {
for(int i=0;i<G[x].size();i++)
if( G[x][i] != f ) dfs1(G[x][i], x, m, p);
}
if( x != 1 ) {
q1[mx[x] - 1].push_back(x);
if( pos[x] == x && mx[mx[x]] > x )
q2[mx[mx[x]] - 1].push_back(x);
}
}
int ans[MAXN + 5], g[MAXN + 5];
void dfs2(int x, int f) {
if( x != 1 ) {
if( pos[x] == x ) g[x] += ans[mx[x]];
ans[x] += g[pos[x]];
}
for(int i=0;i<G[x].size();i++)
if( G[x][i] != f ) dfs2(G[x][i], x);
}
bool tag[MAXN + 5]; int fa[MAXN + 5], siz[MAXN + 5];
int find(int x) {return fa[x] = (fa[x] == x ? x : find(fa[x]));}
void unite(int x, int y) {
int fx = find(x), fy = find(y);
fa[fx] = fy, siz[fy] += siz[fx];
}
void add(int &sum, int x) {
x = find(x);
if( !tag[x] ) {
tag[x] = true;
sum += siz[find(x)];
}
}
void erase(int x) {tag[find(x)] = false;}
int main() {
int N; scanf("%d", &N);
for(int i=1;i<N;i++) {
int u, v; scanf("%d%d", &u, &v);
addedge(u, v);
}
dfs1(1, 0, 0, 1);
for(int i=1;i<=N;i++) fa[i] = i, siz[i] = 1;
for(int i=0;i<=N;i++) {
for(int j=0;j<G[i].size();j++)
if( G[i][j] <= i ) unite(i, G[i][j]);
for(int j=0;j<q1[i].size();j++) {
int x = q1[i][j], s = 0;
for(int p=0;p<G[x].size();p++)
if( G[x][p] <= i ) add(s, G[x][p]);
add(s, x), ans[x] += s;
for(int p=0;p<G[x].size();p++)
if( G[x][p] <= i ) erase(G[x][p]);
erase(x);
}
for(int j=0;j<q2[i].size();j++) {
int x = q2[i][j], s = 0;
for(int p=0;p<G[x].size();p++)
if( G[x][p] <= i ) add(s, G[x][p]);
add(s, x), g[x] -= s;
for(int p=0;p<G[x].size();p++)
if( G[x][p] <= i ) erase(G[x][p]);
erase(x);
}
}
ans[1] = 1; dfs2(1, 0);
for(int i=2;i<=N;i++)
printf("%d%c", ans[i] - 1, (i == N ? '
' : ' '));
}
codeforces - 1039D:最大长度为 i 的链剖分等价于最大长度 >= i 的链剖分。可以类比 noip2018d1t3 的贪心,能够子树内部匹配的就不往子树外部匹配,O(n) 贪心一波。注意到答案单调递减,且对于 i 答案上界为 n/i,因此当 > (O(sqrt{nlog n})) 时二分找相同答案右端点可以做到 (O(nsqrt{nlog n}))。略卡常,将递归换成扫 dfs 序。
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 100000;
const int SQRT = 1100;
vector<int>G[MAXN + 5];
void addedge(int u, int v) {
G[u].push_back(v), G[v].push_back(u);
}
int dfn[MAXN + 5], fa[MAXN + 5], dcnt;
void dfs(int x, int f) {
dfn[++dcnt] = x, fa[x] = f;
for(int i=0;i<G[x].size();i++)
if( G[x][i] != f ) dfs(G[x][i], x);
}
int mx[MAXN + 5], smx[MAXN + 5], f[MAXN + 5], g[MAXN + 5], n;
int solve(int x) {
for(register int i=1;i<=n;i++) mx[i] = smx[i] = f[i] = 0;
for(register int i=n;i>=1;i--) {
int k = dfn[i];
if( mx[k] + smx[k] + 1 >= x )
f[k]++, g[k] = 0;
else g[k] = mx[k] + 1;
if( fa[k] ) {
f[fa[k]] += f[k];
if( g[k] > mx[fa[k]] )
smx[fa[k]] = mx[fa[k]], mx[fa[k]] = g[k];
else if( g[k] > smx[fa[k]] )
smx[fa[k]] = g[k];
}
}
return f[1];
}
int ans[MAXN + 5];
int main() {
scanf("%d", &n);
for(int i=1;i<n;i++) {
int u, v; scanf("%d%d", &u, &v);
addedge(u, v);
}
dfs(1, 0); int p;
for(p = 1; p <= SQRT && p <= n; p++)
ans[p] = solve(p);
for(; p <= n;) {
int x = solve(p), l = p, r = n;
while( l < r ) {
int m = (l + r + 1) >> 1;
if( solve(m) >= x )
l = m;
else r = m - 1;
}
for(; p <= l; p++) ans[p] = x;
}
for(int i=1;i<=n;i++) printf("%d
", ans[i]);
}
hdu - 5306:segment tree beats 模板题。我也不知道为啥跑得很慢。
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1000000;
int read() {
int x = 0; char ch = getchar();
while( ch > '9' || ch < '0' ) ch = getchar();
while( '0' <= ch && ch <= '9' ) x = 10*x + ch - '0', ch = getchar();
return x;
}
void write(ll x, bool _=false) {
if( !x ) {
if( !_ ) putchar('0');
return ;
}
write(x / 10, true), putchar(x % 10 + '0');
}
struct type{
int mx, smx, mc; type() {}
type(int _mx, int _smx, int _mc) : mx(_mx), smx(_smx), mc(_mc) {}
friend type merge(const type &a, const type &b) {
if( a.mx == b.mx ) return type(a.mx, max(a.smx, b.smx), a.mc + b.mc);
else if( a.mx > b.mx ) return type(a.mx, max(a.smx, b.mx), a.mc);
else return type(b.mx, max(a.mx, b.smx), b.mc);
}
};
int a[MAXN + 5], n, m;
namespace segtree{
#define lch (x << 1)
#define rch (x << 1 | 1)
int le[4*MAXN + 5], ri[4*MAXN + 5];
type t[4*MAXN + 5]; ll s[4*MAXN + 5];
void maintain(int x, int k) {
if( k < t[x].mx )
s[x] -= 1LL*(t[x].mx - k)*t[x].mc, t[x].mx = k;
}
void pushdown(int x) {maintain(lch, t[x].mx), maintain(rch, t[x].mx);}
void pushup(int x) {s[x] = s[lch] + s[rch], t[x] = merge(t[lch], t[rch]);}
void build(int x, int l, int r) {
le[x] = l, ri[x] = r;
if( l == r ) {
t[x] = type(a[l], -1, 1); s[x] = a[l];
return ;
}
int m = (l + r) >> 1;
build(lch, l, m), build(rch, m + 1, r);
pushup(x);
}
void modify(int x, int l, int r, int k) {
if( l <= le[x] && ri[x] <= r && t[x].smx < k ) {
maintain(x, k);
return ;
}
if( l > ri[x] || r < le[x] || k >= t[x].mx ) return ;
pushdown(x);
modify(lch, l, r, k), modify(rch, l, r, k);
pushup(x);
}
int query(int x, int l, int r) {
if( l <= le[x] && ri[x] <= r ) return t[x].mx;
if( l > ri[x] || r < le[x] ) return -1;
pushdown(x); return max(query(lch, l, r), query(rch, l, r));
}
ll sum(int x, int l, int r) {
if( l <= le[x] && ri[x] <= r ) return s[x];
if( l > ri[x] || r < le[x] ) return 0;
pushdown(x); return sum(lch, l, r) + sum(rch, l, r);
}
}
void solve() {
n = read(), m = read();
for(int i=1;i<=n;i++) a[i] = read();
segtree::build(1, 1, n);
for(int i=1;i<=m;i++) {
int op = read(), x = read(), y = read(), t;
if( op == 0 ) t = read(), segtree::modify(1, x, y, t);
else if( op == 1 ) write(segtree::query(1, x, y)), puts("");
else write(segtree::sum(1, x, y)), puts("");
}
}
int main() {int _ = read(); while( _-- ) solve();}
bzoj - 4695:稍微复杂一点的 Segment Tree Beats。可以把区间取 max/min 看作区间内 min/max 值整体加减。因为打 tag 会导致 min/max 值变化(反正我写的代码会变化)所以需要先处理出儿子的 min/max 是否与父亲相同。偷了个 fread 刚好卡过。
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = int(1E9);
const int MAXN = 500000;
#define gc if(++ip==ie)fread(ip=buf,1,SZ,stdin)
const int SZ=1<<19;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int read(){
gc;while(*ip<'-')gc;
bool f=*ip=='-';if(f)gc;
int x=*ip&15;gc;
while(*ip>'-'){x*=10;x+=*ip&15;gc;}
return f?-x:x;
}
int A[MAXN + 5], N, M;
namespace segtree{
#define lch (x << 1)
#define rch (x << 1 | 1)
int le[4*MAXN + 5], ri[4*MAXN + 5]; ll sum[4*MAXN + 5];
bool ismx[4*MAXN + 5], ismn[4*MAXN + 5];
int mx[4*MAXN + 5], smx[4*MAXN + 5], cmx[4*MAXN + 5];
int mn[4*MAXN + 5], smn[4*MAXN + 5], cmn[4*MAXN + 5];
int stg[4*MAXN + 5], mxtg[4*MAXN + 5], mntg[4*MAXN + 5];
void pushup(int x) {
sum[x] = sum[lch] + sum[rch];
mx[x] = max(mx[lch], mx[rch]);
if( mx[lch] == mx[rch] ) smx[x] = max(smx[lch], smx[rch]), cmx[x] = cmx[lch] + cmx[rch];
else if( mx[lch] < mx[rch] ) smx[x] = max(mx[lch], smx[rch]), cmx[x] = cmx[rch];
else smx[x] = max(smx[lch], mx[rch]), cmx[x] = cmx[lch];
ismx[lch] = (mx[lch] == mx[x]), ismx[rch] = (mx[rch] == mx[x]);
mn[x] = min(mn[lch], mn[rch]);
if( mn[lch] == mn[rch] ) smn[x] = min(smn[lch], smn[rch]), cmn[x] = cmn[lch] + cmn[rch];
else if( mn[lch] > mn[rch] ) smn[x] = min(mn[lch], smn[rch]), cmn[x] = cmn[rch];
else smn[x] = min(smn[lch], mn[rch]), cmn[x] = cmn[lch];
ismn[lch] = (mn[lch] == mn[x]), ismn[rch] = (mn[rch] == mn[x]);
}
void maintains(int x, int t) {
if( t == 0 ) return ;
stg[x] += t, mx[x] += t, mn[x] += t;
sum[x] += 1LL * t * (ri[x] - le[x] + 1);
if( mn[x] != mx[x] ) smn[x] += t, smx[x] += t;
}
void maintainmx(int x, int t) {
if( mn[x] == mx[x] ) maintains(x, t);
else {
mxtg[x] += t, sum[x] += 1LL * t * cmx[x];
if( mx[x] == smn[x] ) smn[x] += t; mx[x] += t;
}
}
void maintainmn(int x, int t) {
if( mn[x] == mx[x] ) maintains(x, t);
else {
mntg[x] += t, sum[x] += 1LL * t * cmn[x];
if( mn[x] == smx[x] ) smx[x] += t; mn[x] += t;
}
}
void pushdown(int x) {
if( mxtg[x] ) {
if( ismx[lch] ) maintainmx(lch, mxtg[x]);
if( ismx[rch] ) maintainmx(rch, mxtg[x]);
mxtg[x] = 0;
}
if( mntg[x] ) {
if( ismn[lch] ) maintainmn(lch, mntg[x]);
if( ismn[rch] ) maintainmn(rch, mntg[x]);
mntg[x] = 0;
}
if( stg[x] ) maintains(lch, stg[x]), maintains(rch, stg[x]), stg[x] = 0;
}
void build(int x, int l, int r) {
le[x] = l, ri[x] = r, stg[x] = mntg[x] = mxtg[x] = 0;
if( l == r ) {
sum[x] = mx[x] = mn[x] = A[l], smn[x] = INF, smx[x] = -INF, cmn[x] = cmx[x] = 1;
return ;
}
int m = (l + r) >> 1;
build(lch, l, m), build(rch, m + 1, r);
pushup(x);
}
void modifys(int x, int l, int r, int k) {
if( l > ri[x] || r < le[x] ) return ;
if( l <= le[x] && ri[x] <= r ) {
maintains(x, k);
return ;
}
pushdown(x);
modifys(lch, l, r, k), modifys(rch, l, r, k);
pushup(x);
}
void modifymn(int x, int l, int r, int k) {
if( mx[x] <= k ) return ;
if( l > ri[x] || r < le[x] ) return ;
if( l <= le[x] && ri[x] <= r && smx[x] < k ) {
maintainmx(x, k - mx[x]);
return ;
}
pushdown(x);
modifymn(lch, l, r, k), modifymn(rch, l, r, k);
pushup(x);
}
void modifymx(int x, int l, int r, int k) {
if( mn[x] >= k ) return ;
if( l > ri[x] || r < le[x] ) return ;
if( l <= le[x] && ri[x] <= r && smn[x] > k ) {
maintainmn(x, k - mn[x]);
return ;
}
pushdown(x);
modifymx(lch, l, r, k), modifymx(rch, l, r, k);
pushup(x);
}
ll querys(int x, int l, int r) {
if( l > ri[x] || r < le[x] ) return 0;
if( l <= le[x] && ri[x] <= r ) return sum[x];
pushdown(x); return querys(lch, l, r) + querys(rch, l, r);
}
int querymn(int x, int l, int r) {
if( l > ri[x] || r < le[x] ) return INF;
if( l <= le[x] && ri[x] <= r ) return mn[x];
pushdown(x); return min(querymn(lch, l, r), querymn(rch, l, r));
}
int querymx(int x, int l, int r) {
if( l > ri[x] || r < le[x] ) return -INF;
if( l <= le[x] && ri[x] <= r ) return mx[x];
pushdown(x); return max(querymx(lch, l, r), querymx(rch, l, r));
}
}
void write(int x) {
if( x < 0 ) x = -x, putchar('-');
if( x >= 10 ) write(x / 10);
putchar(x % 10 + '0');
}
void write(ll x) {
if( x < 0 ) x = -x, putchar('-');
if( x >= 10 ) write(x / 10);
putchar(x % 10 + '0');
}
int main() {
N = read();
for(int i=1;i<=N;i++) A[i] = read();
segtree::build(1, 1, N);
M = read();
for(int i=1;i<=M;i++) {
int tp = read(), L = read(), R = read();
if( tp <= 3 ) {
int X = read();
if( tp == 1 ) segtree::modifys(1, L, R, X);
else if( tp == 2 ) segtree::modifymx(1, L, R, X);
else segtree::modifymn(1, L, R, X);
} else {
if( tp == 4 ) write(segtree::querys(1, L, R)), puts("");
else if( tp == 5 ) write(segtree::querymx(1, L, R)), puts("");
else write(segtree::querymn(1, L, R)), puts("");
}
}
}
bzoj - 3064:维护标记 max(x + a, b),可以统一题目中的操作,而且可以方便地维护最大值与历史最大值。
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100000;
const ll INF = ll(1E12);
struct type{
ll a, b; type() {}
type(ll _a, ll _b) : a(_a), b(_b) {}
friend type operator + (type a, type b) {
return type(a.a + b.a, max(a.b + b.a, b.b));
} // max(max(x + a.a, a.b) + b.a, b.b)
friend type max(type a, type b) {
return type(max(a.a, b.a), max(a.b, b.b));
} // max(max(x + a.a, a.b), max(x + b.a, b.b))
}; // max(x + a, b)
int A[MAXN + 5], T;
namespace segtree{
#define lch (x << 1)
#define rch (x << 1 | 1)
int le[4*MAXN + 5], ri[4*MAXN + 5];
type tg[4*MAXN + 5], htg[4*MAXN + 5];
type mx[4*MAXN + 5], hmx[4*MAXN + 5];
void pushup(int x) {
mx[x] = max(mx[lch], mx[rch]), hmx[x] = max(hmx[lch], hmx[rch]);
}
void maintain(int x, type t, type ht) {
hmx[x] = max(hmx[x], mx[x] + ht), mx[x] = mx[x] + t;
htg[x] = max(htg[x], tg[x] + ht), tg[x] = tg[x] + t;
}
void pushdown(int x) {
maintain(lch, tg[x], htg[x]);
maintain(rch, tg[x], htg[x]);
tg[x] = htg[x] = type(0, -INF);
}
void build(int x, int l, int r) {
le[x] = l, ri[x] = r, tg[x] = htg[x] = type(0, -INF);
if( l == r ) {
mx[x] = hmx[x] = type(-INF, A[l]);
return ;
}
int m = (l + r) >> 1;
build(lch, l, m), build(rch, m + 1, r);
pushup(x);
}
type query(int x, int l, int r, int t) {
if( l > ri[x] || r < le[x] ) return type(-INF, -INF);
if( l <= le[x] && ri[x] <= r ) return (t == 0 ? mx[x] : hmx[x]);
pushdown(x); return max(query(lch, l, r, t), query(rch, l, r, t));
}
void modify(int x, int l, int r, type k) {
if( l > ri[x] || r < le[x] ) return ;
if( l <= le[x] && ri[x] <= r ) {
maintain(x, k, k);
return ;
}
pushdown(x);
modify(lch, l, r, k), modify(rch, l, r, k);
pushup(x);
}
}
char op[2];
int main() {
scanf("%d", &T);
for(int i=1;i<=T;i++) scanf("%d", &A[i]);
segtree::build(1, 1, T);
int E; scanf("%d", &E);
for(int i=1;i<=E;i++) {
int X, Y; scanf("%s%d%d", op, &X, &Y);
if( op[0] == 'Q' ) {
type ans = segtree::query(1, X, Y, 0);
printf("%lld
", max(ans.a, ans.b));
} else if( op[0] == 'A' ) {
type ans = segtree::query(1, X, Y, 1);
printf("%lld
", max(ans.a, ans.b));
} else if( op[0] == 'P' ) {
int Z; scanf("%d", &Z);
segtree::modify(1, X, Y, type(Z, -INF));
} else {
int Z; scanf("%d", &Z);
segtree::modify(1, X, Y, type(-INF, Z));
}
}
}