loj上只挂了两个无重的题,本来心想水一下,结果被SDOI2011染色那题卡了一发。尽管这题之前做过,但实现很不优美。今天WA的第一发一开始测样例就挂了,强行调试半天交上去一分没有。后来仔细想了想怎样写比较清楚(尽管看起来好像有点冗余),写好以后一路顺风一发就过。从这里也有点感悟吧。
10138. 「一本通 4.5 例 1」树的统计
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1000005;
int n, m, q, t1, t2, t3, t4;
namespace seg {
int a[N], b[N];
void pushup(int p) {
a[p] = max(a[p * 2], a[p * 2 + 1]);
b[p] = b[p * 2] + b[p * 2 + 1];
}
void build(int p, int l, int r, int *src) {
if (l == r) {
a[p] = b[p] = src[l];
} else {
build(p * 2, l, (l + r) / 2, src);
build(p * 2 + 1, (l + r) / 2 + 1, r, src);
pushup(p);
}
}
void modify(int p, int l, int r, int pos, int val) {
if (l == r) {
a[p] = b[p] = val;
} else {
if (pos <= (l + r) / 2) {
modify(p * 2, l, (l + r) / 2, pos, val);
} else {
modify(p * 2 + 1, (l + r) / 2 + 1, r, pos, val);
}
pushup(p);
}
}
int querya(int p, int l, int r, int ql, int qr) {
if (l > qr || r < ql) {
return -1e+9;
}
if (l >= ql && r <= qr) {
return a[p];
} else {
return max(querya(p * 2, l, (l + r) / 2, ql, qr), querya(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr));
}
}
int queryb(int p, int l, int r, int ql, int qr) {
if (l > qr || r < ql) {
return 0;
}
if (l >= ql && r <= qr) {
return b[p];
} else {
return queryb(p * 2, l, (l + r) / 2, ql, qr) + queryb(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr);
}
}
} // namespace seg
namespace tree {
vector<int> g[N];
int vis[N], dep[N], siz[N], wson[N], top[N], fa[N], dfn[N], ind;
void dfs1(int p) {
vis[p] = 1;
siz[p] = 1;
for (int i = 0; i < g[p].size(); i++) {
int q = g[p][i];
if (vis[q])
continue;
fa[q] = p;
dep[q] = dep[p] + 1;
dfs1(q);
siz[p] += siz[q];
if (siz[q] > siz[wson[p]])
wson[p] = q;
}
}
void dfs2(int p) {
vis[p] = 1;
dfn[p] = ++ind;
if (wson[p]) {
top[wson[p]] = top[p];
dfs2(wson[p]);
}
for (int i = 0; i < g[p].size(); i++) {
int q = g[p][i];
if (vis[q])
continue;
top[q] = q;
dfs2(q);
}
}
void presolve() {
memset(vis, 0, sizeof vis);
dfs1(1);
memset(vis, 0, sizeof vis);
top[1] = 1;
dfs2(1);
}
void modify(int p, int val) { seg::modify(1, 1, n, dfn[p], val); }
int querya(int p, int q) {
int ret = -1e+9;
while (top[p] != top[q]) {
if (dep[top[p]] < dep[top[q]])
swap(p, q);
ret = max(ret, seg::querya(1, 1, n, dfn[top[p]], dfn[p]));
p = fa[top[p]];
}
if (dep[p] < dep[q])
swap(p, q);
return max(ret, seg::querya(1, 1, n, dfn[q], dfn[p]));
}
int queryb(int p, int q) {
int ret = 0;
while (top[p] != top[q]) {
if (dep[top[p]] < dep[top[q]])
swap(p, q);
ret += seg::queryb(1, 1, n, dfn[top[p]], dfn[p]);
p = fa[top[p]];
}
if (dep[p] < dep[q])
swap(p, q);
return ret + seg::queryb(1, 1, n, dfn[q], dfn[p]);
}
} // namespace tree
int src[N], tmp[N];
signed main() {
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i < n; i++) {
cin >> t1 >> t2;
tree::g[t1].push_back(t2);
tree::g[t2].push_back(t1);
}
tree::presolve();
for (int i = 1; i <= n; i++) {
cin >> tmp[i];
}
for (int i = 1; i <= n; i++) {
src[tree::dfn[i]] = tmp[i];
}
seg::build(1, 1, n, src);
cin >> q;
for (int i = 1; i <= q; i++) {
string op;
cin >> op >> t1 >> t2;
if (op[1] == 'H') {
tree::modify(t1, t2);
}
if (op[1] == 'M') {
cout << tree::querya(t1, t2) << endl;
}
if (op[1] == 'S') {
cout << tree::queryb(t1, t2) << endl;
}
}
}
10141. 「一本通 4.5 练习 3」染色
这题的思路很常规,无非就是线段树每个节点除了维护答案多维护左边和右边的颜色,然后由于这个答案可以被快速合并,暴力一下就可以了。
线段树的部分毕竟都是按顺序的所以很容易。但树链剖分查询的时候由于顺序翻转之类的问题,开个结构体以后事情变得清楚了很多。
类似的问题还有很多,比如维护最大字段和,加等差数列求和等等,把结点对象稍微封装一下其实就会很容易。当然自己码力太弱才是真原因啊~~
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005;
int n, m, t1, t2, t3, t4, src[N], tmp[N];
namespace seg {
int a[N], al[N], ar[N], tg[N];
void pushup(int p) {
al[p] = al[p * 2];
ar[p] = ar[p * 2 + 1];
a[p] = a[p * 2] + a[p * 2 + 1] - (al[p * 2 + 1] == ar[p * 2] ? 1 : 0);
}
void pushdown(int p) {
if (tg[p] == 0)
return;
tg[p * 2] = tg[p * 2 + 1] = tg[p];
a[p * 2] = a[p * 2 + 1] = 1;
al[p * 2] = al[p * 2 + 1] = tg[p];
ar[p * 2] = ar[p * 2 + 1] = tg[p];
tg[p] = 0;
}
void build(int p, int l, int r, int *src) {
if (l == r) {
a[p] = 1;
al[p] = ar[p] = src[l];
} else {
build(p * 2, l, (l + r) / 2, src);
build(p * 2 + 1, (l + r) / 2 + 1, r, src);
pushup(p);
}
}
void modify(int p, int l, int r, int ql, int qr, int val) {
if (l > qr || r < ql)
return;
if (l >= ql && r <= qr) {
tg[p] = al[p] = ar[p] = val;
a[p] = 1;
} else {
pushdown(p);
modify(p * 2, l, (l + r) / 2, ql, qr, val);
modify(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr, val);
pushup(p);
}
}
int query(int p, int l, int r, int ql, int qr, int &rl, int &rr) {
if (l > qr || r < ql)
return 0;
if (l >= ql && r <= qr) {
rl = al[p];
rr = ar[p];
return a[p];
} else {
pushdown(p);
int l1 = 0, r1 = 0, l2 = 0, r2 = 0, s1 = 0, s2 = 0;
s1 = query(p * 2, l, (l + r) / 2, ql, qr, l1, r1);
s2 = query(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr, l2, r2);
rl = l1;
rr = r2;
if (rl == 0)
rl = l2;
if (rr == 0)
rr = r1;
return s1 + s2 - ((r1 && r1 == l2) ? 1 : 0);
}
}
int query(int ql, int qr, int &rl, int &rr) {
int tmp = query(1, 1, n, ql, qr, rl, rr);
// cout<<" query "<<ql<<", "<<qr<<" = "<<tmp<<" : "<<rl<<","<<rr<<endl;
return tmp;
}
} // namespace seg
namespace tree {
vector<int> g[N];
int top[N], dep[N], siz[N], wson[N], fa[N], vis[N], dfn[N], ind;
void dfs1(int p) {
vis[p] = 1;
siz[p] = 1;
for (int i = 0; i < g[p].size(); i++) {
int q = g[p][i];
if (vis[q])
continue;
fa[q] = p;
dep[q] = dep[p] + 1;
dfs1(q);
siz[p] += siz[q];
if (siz[q] > siz[wson[p]])
wson[p] = q;
}
}
void dfs2(int p) {
vis[p] = 1;
dfn[p] = ++ind;
if (wson[p]) {
top[wson[p]] = top[p];
dfs2(wson[p]);
}
for (int i = 0; i < g[p].size(); i++) {
int q = g[p][i];
if (vis[q])
continue;
top[q] = q;
dfs2(q);
}
}
void presolve() {
memset(vis, 0, sizeof vis);
dfs1(1);
memset(vis, 0, sizeof vis);
top[1] = 1;
dfs2(1);
}
struct Result {
int ans = 0, cl = 0, cr = 0;
void get(int ql, int qr) { ans = seg::query(ql, qr, cl, cr); }
};
Result merge(Result a, Result b) {
Result ret;
ret.ans = a.ans + b.ans - (a.cr == b.cl ? 1 : 0);
ret.cl = a.cl;
ret.cr = b.cr;
return ret;
}
int query(int p, int q) {
if (dfn[p] > dfn[q])
swap(p, q);
Result ret[2];
int inv = 0;
while (top[p] != top[q]) {
if (dep[top[p]] < dep[top[q]])
swap(p, q), inv ^= 1;
Result tmp;
tmp.get(dfn[top[p]], dfn[p]);
ret[inv] = merge(tmp, ret[inv]);
p = fa[top[p]];
}
if (dep[p] < dep[q])
swap(p, q), inv ^= 1;
Result tmp;
tmp.get(dfn[q], dfn[p]);
ret[inv] = merge(tmp, ret[inv]);
swap(ret[0].cl, ret[0].cr);
Result ans = merge(ret[0], ret[1]);
return ans.ans;
}
void modify(int p, int q, int v) {
while (top[p] != top[q]) {
if (dep[top[p]] < dep[top[q]])
swap(p, q);
seg::modify(1, 1, n, dfn[top[p]], dfn[p], v);
p = fa[top[p]];
}
if (dep[p] < dep[q])
swap(p, q);
seg::modify(1, 1, n, dfn[q], dfn[p], v);
}
} // namespace tree
int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> tmp[i];
for (int i = 1; i < n; i++) {
cin >> t1 >> t2;
tree::g[t1].push_back(t2);
tree::g[t2].push_back(t1);
}
tree::presolve();
for (int i = 1; i <= n; i++) src[tree::dfn[i]] = tmp[i];
seg::build(1, 1, n, src);
for (int i = 1; i <= m; i++) {
char op;
cin >> op;
if (op == 'C') {
cin >> t1 >> t2 >> t3;
tree::modify(t1, t2, t3);
} else {
cin >> t1 >> t2;
cout << tree::query(t1, t2) << endl;
}
}
return 0;
}