Subtree Removal

很显然不可能选择砍掉一对有祖先关系的子树。令$f_i$表示$i$子树的答案,如果$i$不被砍,那就是$a_i + \sum\limits_j f_j$;如果$i$被砍,那就是$-x$。取个$max$就好了。

时间、空间复杂度$O(n)$。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + ;

int tc, n, xx;
int a[N];
vector<int> g[N];
long long f[N]; void Dfs(int x, int ft) {
f[x] = a[x];
for (int i = ; i < g[x].size(); ++i) {
int v = g[x][i];
if (v == ft) continue;
Dfs(v, x);
f[x] += f[v];
}
f[x] = max(f[x], -(long long)xx);
} int main() {
scanf("%d", &tc);
for (; tc--; ) {
scanf("%d%d", &n, &xx);
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
}
for (int i = , x, y; i < n; ++i) {
scanf("%d%d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
} Dfs(, );
printf("%lld\n", f[]); // remember to clear up
for (int i = ; i <= n; ++i) {
g[i].clear();
}
} return ;
}

Playing with Numbers

在模$m$意义下,$a * k(k \in \mathbb{N})$能表示的最大的数就是$m - (a, m)$。容易推导出一个叶子的答案就是$m_i - (m, a_{b_1}, a_{b_2}, ... , a_{b_w})$,其中$b$表示$i$号点的祖先链。

时间复杂度$O(nlogn)$,空间复杂度$O(n)$。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + ;

int tc, n;
vector<int> g[N];
long long a[N], m[N], gcd[N]; void Dfs(int x, int ft) {
for (int i = ; i < g[x].size(); ++i) {
int v = g[x][i];
if (v == ft) continue;
gcd[v] = __gcd(gcd[x], a[v]);
Dfs(v, x);
}
} int main() {
scanf("%d", &tc);
for (; tc--; ) {
scanf("%d", &n);
for (int i = , x, y; i < n; ++i) {
scanf("%d%d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
for (int i = ; i <= n; ++i) {
scanf("%lld", &a[i]);
}
for (int i = ; i <= n; ++i) {
scanf("%lld", &m[i]);
}
gcd[] = a[];
Dfs(, ); for (int i = ; i <= n; ++i) {
if (g[i].size() == ) {
long long d = __gcd(gcd[i], m[i]);
printf("%lld ", m[i] - d);
}
}
printf("\n"); // remember to clear up
for (int i = ; i <= n; ++i) {
g[i].clear();
}
} return ;
}

Kira Loves Palindromes

令$f_{i,j}$表示以$i,j$为端点分别向左右两边扩展最长能匹配的长度。题目要求两个子串$s1, s2$拼起来是回文串的数量,我们假设其回文中心在$s2$里(在$s1$的话反过来在做一遍即可),我们枚举$s2$的左端点的位置$i$,在枚举回文中心的右端点$j$,则此时有方案数$\sum\limits_{k = 1}^{i - 1} f_{k, j + 1}$。对$f$做个前缀和,外面枚举个$i,j$即可。

时间、空间复杂度$O(n^2)$。

#include <bits/stdc++.h>

using namespace std;

typedef unsigned long long ULL;

const int N = 1e3 + ;
const ULL BAS = ; int n;
char s[N];
int f[N][N], s1[N][N], s2[N][N];
long long ans;
ULL H[N], hz[N], hv[N]; ULL Get(int l, int r, ULL *h) {
return (h[r] - h[l - ]) * H[N - l];
} bool Chkp(int l, int r) {
if (l > r) return ;
int d = (r - l + ) / ;
return Get(l, l + d - , hz) == Get(n - r + , n - r + d, hv);
} int main() {
H[] = ;
for (int i = ; i < N; ++i) {
H[i] = H[i - ] * BAS;
} scanf("%s", s + );
n = strlen(s + );
for (int i = ; i <= n; ++i) {
hz[i] = hz[i - ] + H[i] * s[i];
hv[i] = hv[i - ] + H[i] * s[n - i + ];
} for (int i = ; i <= n; ++i) {
for (int j = n; j > i; --j) {
if (s[i] == s[j]) {
f[i][j] = f[i - ][j + ] + ;
}
}
}
for (int i = ; i <= n; ++i) {
for (int j = n; j > i; --j) {
s1[i][j] = s1[i][j + ] + f[i][j];
}
}
for (int j = ; j <= n; ++j) {
for (int i = ; i < j; ++i) {
s2[i][j] = s2[i - ][j] + f[i][j];
}
} for (int i = ; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
if (!Chkp(i, j - )) continue;
ans += s2[i - ][j];
}
}
for (int i = ; i < n; ++i) {
for (int j = ; j < i; ++j) {
if (!Chkp(j + , i)) continue;
ans += s1[j][i + ];
}
} printf("%lld\n", ans); return ;
}

Offer for Chef

题中的那个运算就是位运算与,然后有用的位置只有$50$个(即如果$k$大于$t$中非$0$个数答案就是$0$)。可以考虑诸位确定,$check$时写个$f_{i,j}$表示把前$i$个数分成$j$段,每段和都是当前要$check$的数的母集即可。

时间复杂度$O(50^4)$,空间复杂度$O(n)$。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + ;
const int M = ; int n, nq, k;
int t[N];
long long a[N];
set<long long> f[M][M]; int main() {
scanf("%d", &n);
for (int i = ; i <= n; ++i) {
scanf("%lld", &a[i]);
} scanf("%d", &nq);
for (; nq--; ) {
scanf("%d", &k);
vector<long long> w, sw;
long long tmp = ;
for (int i = ; i <= n; ++i) {
scanf("%d", &t[i]);
if (t[i]) {
w.push_back(a[i] * t[i]);
tmp += a[i] * t[i];
sw.push_back(tmp);
}
} if (k > w.size()) {
printf("0\n");
continue;
} for (int i = ; i < M; ++i) {
for (int j = ; j < M; ++j) {
f[i][j].clear();
}
}
for (int i = ; i < w.size(); ++i) {
f[i][].insert(sw[i]);
} for (int i = ; i < w.size(); ++i) {
for (int j = ; j < k; ++j) {
for (int l = i + ; l < w.size(); ++l) {
for (long long e : f[i][j]) {
f[l][j + ].insert(e & (sw[l] - sw[i]));
}
}
}
}
printf("%lld\n", *f[w.size() - ][k].rbegin());
} return ;
}

Mininum XOR over Tree

不说了,直接$trie$树合并。

时间、空间复杂度$O(nlogn)$。

#include <bits/stdc++.h>

using namespace std;

const int T = ;
const int N = 2e5 + ;
const int M = N * T * ; struct Node {
int ch[], idm;
} node[M]; int tc, n, m, nq, tot;
int w[N], rt[N];
vector<int> g[N]; int Chkmin(int x, int y) {
if (!x || !y) return x | y;
return min(x, y);
} void Ins(int x) {
rt[x] = ++tot;
int p = rt[x];
for (int i = T - ; ~i; --i) {
int c = w[x] >> i & ;
if (!node[p].ch[c]) {
node[p].ch[c] = ++tot;
}
p = node[p].ch[c];
}
node[p].idm = x;
} int Merge(int x, int y) {
if (!x || !y) return x | y;
int z = ++tot;
node[z].ch[] = Merge(node[x].ch[], node[y].ch[]);
node[z].ch[] = Merge(node[x].ch[], node[y].ch[]);
node[z].idm = Chkmin(node[x].idm, node[y].idm);
return z;
} void Dfs(int x, int ft) {
Ins(x);
for (int i = ; i < g[x].size(); ++i) {
int v = g[x][i];
if (v == ft) continue;
Dfs(v, x);
rt[x] = Merge(rt[x], rt[v]);
}
} int main() {
scanf("%d", &tc);
for (; tc--; ) {
scanf("%d%d", &n, &nq);
for (int i = ; i <= n; ++i) {
scanf("%d", &w[i]);
}
for (int i = , x, y; i < n; ++i) {
scanf("%d%d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
Dfs(, ); int lid = , lval = ;
for (int x, v; nq--; ) {
scanf("%d%d", &x, &v);
x ^= lid;
v ^= lval;
int p = rt[x], val = ;
for (int i = T - ; ~i; --i) {
int c = v >> i & ;
if (node[p].ch[c ^ ]) {
val += << i;
p = node[p].ch[c ^ ];
} else {
p = node[p].ch[c];
}
}
lid = node[p].idm;
lval = val;
printf("%d %d\n", lid, lval);
} // remember to clear up
for (int i = ; i <= tot; ++i) {
node[i].ch[] = node[i].ch[] = node[i].idm = ;
}
tot = ;
for (int i = ; i <= n; ++i) {
g[i].clear();
rt[i] = ;
}
} return ;
}

Edgy

考虑边的联通块个数就是$n - $所有出边颜色都相同的点的个数$+1$。我们只需要维护所有出边颜色都相同的点的个数即可。先轻重链剖分,令$nat_x$表示所有连向虚儿子的边的颜色种类(用$0$表示没有虚儿子,用$1,2$分别表示全都是$0/1$,用$3$表示$0/1$都有),然后每个点最多还剩下两条边(连向父亲的和连向重儿子的),只有这两条边的颜色和$nat$匹配才会算贡献。我们可以在树链上建线段树,维护翻转标记的同时维护区间内有贡献的点的个数。每次修改拆成两条到根的链,在线段树上执行区间翻转即可。注意,翻转轻边时候可能会修改该边上端点的$nat$值。

时间复杂度$O(nlog^2n)$,空间复杂度$O(n)$。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + ;

int tc, n, nq, clk, ans;
int fa[N], fw[N], si[N], so[N], tp[N];
int dfn[N], li[N], nat[N], cnt[N][];
vector<pair<int, bool> > g[N]; bool Satis(int x, int a, int b) {
if (a != b) return ;
if (!nat[x] || nat[x] == a + ) return ;
return ;
} namespace S {
const int M = N * ;
struct Node {
int zl, zr, zsum, revsum, flp;
} node[M]; vector<pair<Node, int> > qry; void Up(int t, int md) {
Node &now = node[t];
Node &ls = node[t << ];
Node &rs = node[t << | ];
now.zl = ls.zl;
now.zr = rs.zr;
now.zsum = ls.zsum + rs.zsum + Satis(li[md], ls.zr, rs.zl);
now.revsum = ls.revsum + rs.revsum + Satis(li[md], ls.zr ^ , rs.zl ^ );
} void Uflp(int t) {
Node &now = node[t];
now.zl ^= ;
now.zr ^= ;
now.flp ^= ;
swap(now.zsum, now.revsum);
} void Down(int t) {
if (node[t].flp) {
Uflp(t << );
Uflp(t << | );
node[t].flp = ;
}
} void Build(int t, int l, int r) {
Node &now = node[t];
now.zsum = now.revsum = now.flp = ;
if (l == r) {
now.zl = now.zr = fw[li[l]];
return;
}
int md = (l + r) >> ;
Build(t << , l, md);
Build(t << | , md + , r);
Up(t, md);
} void Flip(int t, int l, int r, int L, int R) {
if (L <= l && r <= R) {
Uflp(t);
return;
}
int md = (l + r) >> ;
Down(t);
if (L <= md) Flip(t << , l, md, L, R);
if (R > md) Flip(t << | , md + , r, L, R);
Up(t, md);
} void Modify(int t, int l, int r, int x) {
if (l == r) return;
int md = (l + r) >> ;
Down(t);
if (x < md) Modify(t << , l, md, x);
if (x > md) Modify(t << | , md + , r, x);
Up(t, md);
} void Query(int t, int l, int r, int L, int R) {
if (L <= l && r <= R) {
qry.push_back(pair<Node, int>(node[t], r));
return;
}
int md = (l + r) >> ;
Down(t);
if (L <= md) Query(t << , l, md, L, R);
if (R > md) Query(t << | , md + , r, L, R);
} int Ask(int t, int l, int r, int x) {
if (l == r) return node[t].zl;
int md = (l + r) >> ;
Down(t);
if (x <= md) return Ask(t << , l, md, x);
return Ask(t << | , md + , r, x);
} int Query(int L, int R) {
if (L > R) return ;
qry.clear();
Query(, , n, L, R);
int ret = ;
for (int i = ; i < qry.size(); ++i) {
ret += qry[i].first.zsum;
if (i) {
ret += Satis(li[qry[i - ].second], qry[i - ].first.zr, qry[i].first.zl);
}
}
return ret;
}
} bool Chk(int x) {
if (x == ) {
int ws = S::Ask(, , n, dfn[so[x]]);
return Satis(x, ws, ws);
}
if (!so[x]) {
int w = S::Ask(, , n, dfn[x]);
return Satis(x, w, w);
} else {
int w = S::Ask(, , n, dfn[x]);
int ws = S::Ask(, , n, dfn[so[x]]);
return Satis(x, ws, w);
}
} void Wish(int x) {
if (cnt[x][] && cnt[x][]) {
nat[x] = ;
} else if (cnt[x][]) {
nat[x] = ;
} else if (cnt[x][]) {
nat[x] = ;
}
} void Dfs0(int x) {
si[x] = ;
for (int i = ; i < g[x].size(); ++i) {
int v = g[x][i].first, w = g[x][i].second;
if (v == fa[x]) continue;
fa[v] = x;
fw[v] = w;
Dfs0(v);
si[x] += si[v];
if (si[v] > si[so[x]]) so[x] = v;
}
} void Dfs1(int x, int gr) {
tp[x] = gr;
dfn[x] = ++clk;
li[clk] = x;
if (so[x]) Dfs1(so[x], gr);
for (int i = ; i < g[x].size(); ++i) {
int v = g[x][i].first;
if (v != fa[x] && v != so[x]) {
Dfs1(v, v);
++cnt[x][g[x][i].second];
}
}
Wish(x);
} void Flip(int u) {
for (int x = u; x; x = fa[tp[x]]) {
ans -= S::Query(dfn[tp[x]] + , dfn[x]);
ans -= Chk(tp[x]) + (tp[x] != x? Chk(x) : );
}
for (int x = u; x; x = fa[tp[x]]) {
int z = tp[x];
int y = fa[z];
if (y) {
int w = S::Ask(, , n, dfn[z]);
--cnt[y][w];
++cnt[y][w ^ ];
Wish(y);
S::Modify(, , n, dfn[y]);
}
S::Flip(, , n, dfn[tp[x]], dfn[x]);
}
for (int x = u; x; x = fa[tp[x]]) {
ans += S::Query(dfn[tp[x]] + , dfn[x]);
ans += Chk(tp[x]) + (tp[x] != x? Chk(x) : );
}
} int main() {
scanf("%d", &tc);
for (; tc--; ) {
scanf("%d", &n);
for (int i = , x, y, z; i < n; ++i) {
scanf("%d%d%d", &x, &y, &z);
g[x].push_back(pair<int, bool>(y, z));
g[y].push_back(pair<int, bool>(x, z));
} Dfs0();
Dfs1(, );
S::Build(, , n); ans = ;
for (int i = ; i <= n; ++i) {
if (!so[i]) {
++ans;
if (tp[i] != i) {
ans += Chk(tp[i]);
ans += S::Query(dfn[tp[i]] + , dfn[i]);
}
}
} scanf("%d", &nq);
for (int u, v; nq--; ) {
scanf("%d%d", &u, &v);
Flip(u);
Flip(v);
printf("%d\n", (n == )? : n - ans + );
} // remember to clear up
clk = ;
for (int i = ; i <= n; ++i) {
g[i].clear();
so[i] = tp[i] = nat[i] = cnt[i][] = cnt[i][] = ;
}
} return ;
}

Sonya and Queries

(被象飞了,写了4个小时)

我们暂且不考虑操作$7$。如果只有前六个操作,大概就是要实现一个数据结构,支持:1,在原树的基础上$link/cut$;2,整个联通块加上一个正数;3,整个联通块赋值为$0$;4,联通块求和;5,单点加,单点查询。由于只有子树的相关操作,所以这些都可以用$ETT$直接解决,也十分好写,只要实现一棵平衡树维护双括号序,$link/cut$时只要$merge/split$就行了。

操作$7$,其要求所有有值的联通块构成的虚树的边数(也就是点数)。考虑如果我们现在有一棵以联通块为点构成的树$T'$,记$cnt_x$表示$x$的子树里有值的点的个数,令$tot$为$T'$点的个数,则要求的虚树的点数为:$tot - \sum\limits_{i = 1}^{tot}[cnt_i = 0] - \sum\limits_{i = 1}^{tot}[cnt_i = cnt_{root}] + 1$。如果某一个点是$0$是$1$的状态改变了,相当于对该点的祖先链的$cnt$执行$+1$或$-1$,实现起来简单点的话可以直接轻重链剖分,用线段树维护树链,并且记录区间内最大值及其个数,最小值及其个数,$\sum\limits_{i = 1}^{tot}[cnt_i = 0]$就是全局最小值的个数(如果最小值是$0$的话),$\sum\limits_{i = 1}^{tot}[cnt_i = cnt_{root}]$就是全局最大值的个数。回到原树上,我们把每个联通块的贡献算到该联通块的根上,即只用其根来标志这个联通块,每个$1$~$6$操作后可能会改掉某个联通块是否有值的状态,也可能会增加或取消某个用于标记联通块的点,这些都扔到线段树上改改就行了。

时间复杂度$O(nlog^2n)$,空间复杂度$O(n)$。

#include <bits/stdc++.h>

using namespace std;

const int N = 2.5e5 + ;
const int INF = 1e9 + ;
const pair<int, int> PINF = pair<int, int>(INF, );
const pair<int, int> PFNI = pair<int, int>(-INF, ); int n, nq, tot, clk;
int tv[N * ], bel[N], fw[N], valsub[N], ival[N];
vector<int> g[N];
int fa[N], si[N], so[N], tp[N], dep[N], dfn[N], li[N];
bool usd[N];
char av[N]; namespace S {
struct Node {
pair<int, int> mn, mx;
int tagadd, cnt;
} node[N * ]; pair<int, int> Comb_min(pair<int, int> a, pair<int, int> b) {
if (a.first < b.first) {
return a;
} else if (a.first > b.first) {
return b;
} else {
return pair<int, int>(a.first, a.second + b.second);
}
} pair<int, int> Comb_max(pair<int, int> a, pair<int, int> b) {
if (a.first > b.first) {
return a;
} else if (a.first < b.first) {
return b;
} else {
return pair<int, int>(a.first, a.second + b.second);
}
} void Up(int t) {
node[t].mn = Comb_min(node[t << ].mn, node[t << | ].mn);
node[t].mx = Comb_max(node[t << ].mx, node[t << | ].mx);
} void Uadd(int t, int _v) {
Node &nw = node[t];
nw.tagadd += _v;
nw.cnt += _v;
nw.mn.first += _v;
nw.mx.first += _v;
} void Down(int t) {
if (node[t].tagadd) {
Uadd(t << , node[t].tagadd);
Uadd(t << | , node[t].tagadd);
node[t].tagadd = ;
}
} void Build(int t, int l, int r) {
if (l == r) {
node[t].cnt = valsub[li[l]];
node[t].mn = usd[li[l]]? pair<int, int>(node[t].cnt, ) : PINF;
node[t].mx = usd[li[l]]? pair<int, int>(node[t].cnt, ) : PFNI;
return;
}
int md = (l + r) >> ;
Build(t << , l, md);
Build(t << | , md + , r);
Up(t);
} void Modify(int t, int l, int r, int L, int R, int _v) {
if (L <= l && r <= R) {
Uadd(t, _v);
return;
}
int md = (l + r) >> ;
Down(t);
if (L <= md) Modify(t << , l, md, L, R, _v);
if (R > md) Modify(t << | , md + , r, L, R, _v);
Up(t);
} void Change_usd(int t, int l, int r, int x) {
if (l == r) {
node[t].mn = usd[li[l]]? pair<int, int>(node[t].cnt, ) : PINF;
node[t].mx = usd[li[l]]? pair<int, int>(node[t].cnt, ) : PFNI;
return;
}
int md = (l + r) >> ;
Down(t);
if (x <= md) Change_usd(t << , l, md, x);
else Change_usd(t << | , md + , r, x);
Up(t);
} pair<int, int> Query_min(int t, int l, int r, int L, int R) {
if (L <= l && r <= R) {
return node[t].mn;
}
int md = (l + r) >> ;
Down(t);
pair<int, int> re = PINF;
if (L <= md) re = Comb_min(re, Query_min(t << , l, md, L, R));
if (R > md) re = Comb_min(re, Query_min(t << | , md + , r, L, R));
return re;
} pair<int, int> Query_max(int t, int l, int r, int L, int R) {
if (L <= l && r <= R) {
return node[t].mx;
}
int md = (l + r) >> ;
Down(t);
pair<int, int> re = PFNI;
if (L <= md) re = Comb_max(re, Query_max(t << , l, md, L, R));
if (R > md) re = Comb_max(re, Query_max(t << | , md + , r, L, R));
return re;
} } int li2[N * ], st[N * ], ed[N * ], clk2; namespace T {
struct Node {
int lc, rc, p, sz, rnd, tagcov;
long long val, sum, tagadd;
} node[N * ]; void Up(int t) {
node[t].sum = node[t].val + node[node[t].lc].sum + node[node[t].rc].sum;
node[t].sz = + node[node[t].lc].sz + node[node[t].rc].sz;
} void Ucov(int t) {
Node &nw = node[t];
nw.val = nw.sum = nw.tagadd = ;
nw.tagcov = ;
} void Uadd(int t, long long _v) {
Node &nw = node[t];
nw.val += _v;
nw.tagadd += _v;
nw.sum += _v * nw.sz;
} void Down(int t) {
Node &nw = node[t];
if (nw.tagcov) {
if (nw.lc) Ucov(nw.lc);
if (nw.rc) Ucov(nw.rc);
nw.tagcov = ;
}
if (nw.tagadd) {
if (nw.lc) Uadd(nw.lc, nw.tagadd);
if (nw.rc) Uadd(nw.rc, nw.tagadd);
nw.tagadd = ;
}
} void Split(int t, int k, int &x, int &y) {
if (!k) {
x = ;
y = t;
return;
}
Down(t);
if (k <= node[node[t].lc].sz) {
y = t;
node[node[t].lc].p = ;
Split(node[t].lc, k, x, node[t].lc);
node[node[t].lc].p = t;
} else {
x = t;
node[node[t].rc].p = ;
Split(node[t].rc, k - node[node[t].lc].sz - , node[t].rc, y);
node[node[t].rc].p = t;
}
Up(t);
} int Merge(int x, int y) {
if (!x || !y) {
return x | y;
}
if (node[x].rnd < node[y].rnd) {
Down(x);
node[x].rc = Merge(node[x].rc, y);
node[node[x].rc].p = x;
Up(x);
return x;
} else {
Down(y);
node[y].lc = Merge(x, node[y].lc);
node[node[y].lc].p = y;
Up(y);
return y;
}
} int Rank(int x) {
int ret = node[node[x].lc].sz;
while (node[x].p) {
if (x == node[node[x].p].rc) {
x = node[x].p;
ret += node[node[x].lc].sz + ;
} else {
x = node[x].p;
}
}
return ret + ;
} void Roll(int x) {
if (node[x].p) {
Roll(node[x].p);
}
Down(x);
} void Wish(int x, long long _v) {
Roll(x);
node[x].val = _v;
while (x) {
Up(x);
x = node[x].p;
}
} long long Thanks(int x) {
Roll(x);
return node[x].val;
} int Find_root(int x) {
while (node[x].p) {
x = node[x].p;
}
return x;
} int Gen(int x) {
while (node[x].lc) {
x = node[x].lc;
}
return x;
} } void Dfs0(int x) {
si[x] = ;
valsub[x] = ival[x] > ;
for (int i = ; i < g[x].size(); ++i) {
int e = g[x][i], v = tv[e];
if (v == fa[x]) continue;
fa[v] = x;
dep[v] = dep[x] + ;
bel[e / ] = v;
fw[v] = e / ;
Dfs0(v);
si[x] += si[v];
if (si[v] > si[so[x]]) so[x] = v;
valsub[x] += valsub[v];
}
} void Dfs1(int x, int gr) {
dfn[x] = ++clk;
li[clk] = x; st[x] = ++clk2;
li2[clk2] = x;
T::node[clk2] = (T::Node){ , , , , rand(), , ival[x], ival[x], }; tp[x] = gr;
if (so[x]) {
Dfs1(so[x], gr);
}
for (int i = ; i < g[x].size(); ++i) {
int e = g[x][i], v = tv[e];
if (v != fa[x] && v != so[x]) {
Dfs1(v, v);
}
} ed[x] = ++clk2;
li2[clk2] = x;
T::node[clk2] = (T::Node){ , , , , rand(), , ival[x], ival[x], };
T::Merge(st[x], ed[x]);
} void Chain_update(int x, int _v) {
while (x) {
S::Modify(, , n, dfn[tp[x]], dfn[x], _v);
x = fa[tp[x]];
}
} void Cut_from_father(int x) {
int l = st[x], r = ed[x];
int rkl = T::Rank(l), rkr = T::Rank(r);
int rt = T::Find_root(l);
long long lsv = T::node[rt].sum;
static int a, b, c;
T::Split(rt, rkr, b, c);
T::Split(b, rkl - , a, b);
rt = T::Merge(a, c);
usd[x] = ;
++tot;
S::Change_usd(, , n, dfn[x]);
if (T::node[b].sum > ) {
Chain_update(x, );
}
if (lsv > && T::node[rt].sum == ) {
int ge = li2[T::Gen(rt)];
Chain_update(ge, -);
}
} void Link_to_father(int x) {
int y = fa[x];
int rkl = T::Rank(st[y]);
int rt = T::Find_root(st[y]);
long long lsv = T::node[rt].sum;
static int a, b, c;
T::Split(rt, rkl, a, c);
b = T::Find_root(st[x]);
if (T::node[b].sum > ) {
Chain_update(x, -);
}
usd[x] = ;
--tot;
S::Change_usd(, , n, dfn[x]);
rt = T::Merge(T::Merge(a, b), c);
if (lsv == && T::node[rt].sum > ) {
int ge = li2[T::Gen(rt)];
Chain_update(ge, );
}
} int main() {
scanf("%*d%d%d", &n, &nq);
tot = n;
for (int i = , x, y; i < n; ++i) {
scanf("%d%d", &x, &y);
tv[i * ] = y;
g[x].push_back(i * );
tv[i * + ] = x;
g[y].push_back(i * + );
} scanf("%s", av + );
for (int i = ; i <= n; ++i) {
scanf("%d", &ival[i]);
usd[i] = ;
} Dfs0();
Dfs1(, );
S::Build(, , n); for (int i = ; i < n; ++i) {
av[i] -= '';
if (av[i] == ) {
Link_to_father(bel[i]);
}
} for (int ty, x, y; nq--; ) {
scanf("%d", &ty);
if (ty != ) {
scanf("%d", &x);
} if (ty == ) {
av[x] ^= ;
if (av[x] == ) {
Cut_from_father(bel[x]);
} else {
Link_to_father(bel[x]);
}
} if (ty == ) {
scanf("%d", &y);
if (y != ) {
int rt = T::Find_root(st[x]);
long long lsv = T::node[rt].sum;
T::Uadd(rt, y);
if (!lsv) {
int ge = li2[T::Gen(rt)];
Chain_update(ge, );
}
}
} if (ty == ) {
int rt = T::Find_root(st[x]);
long long sum = T::node[rt].sum / ;
T::Ucov(rt);
T::Wish(st[x], sum);
T::Wish(ed[x], sum);
} if (ty == ) {
printf("%lld\n", T::Thanks(st[x]));
} if (ty == ) {
int rt = T::Find_root(st[x]);
long long sum = T::node[rt].sum;
printf("%lld\n", sum / );
} if (ty == ) {
int rt = T::Find_root(st[x]);
long long lsv = T::node[rt].sum;
T::Ucov(rt);
if (lsv) {
int ge = li2[T::Gen(rt)];
Chain_update(ge, -);
}
} if (ty == ) {
int res = tot;
res -= S::Query_max(, , n, , n).second - ;
pair<int, int> mim = S::Query_min(, , n, , n);
if (mim.first == ) {
res -= mim.second;
}
printf("%d\n", max(, res - ));
} if (ty == || ty == || ty== ) {
fflush(stdout);
}
} return ;
}

【Code Chef】April Challenge 2019的更多相关文章

  1. Codechef April Challenge 2019 游记

    Codechef April Challenge 2019 游记 Subtree Removal 题目大意: 一棵\(n(n\le10^5)\)个结点的有根树,每个结点有一个权值\(w_i(|w_i\ ...

  2. 关于注释【code templates】,如何导入本地注释文件

    关于如何在eclipse.myeclipse导入本地注释文件 [xxx.xml]   请看操作方式 下面是code templates文件的内容 注意  把文件中的 @@@@@@@@@@@@@@@  ...

  3. 【CodeChef】December Challenge 2019 Div1 解题报告

    点此进入比赛 这次比赛本来想好好打的,但不幸的是,这周先是要认真复习准备月考,考完又是发烧在床上躺了一个周末,所以最终没能打完. 我还是好弱啊. \(T1\):Binary XOR(点此看题面) 大致 ...

  4. 【CodeChef】August Challenge 2019 Div2 解题报告

    点此进入比赛 \(T1\):Football(点此看题面) 大致题意: 求\(max(20a_i-10b_i,0)\). 送分题不解释. #include<bits/stdc++.h> # ...

  5. 【UVALive - 5131】Chips Challenge(上下界循环费用流)

    Description A prominent microprocessor company has enlisted your help to lay out some interchangeabl ...

  6. CodeChef April Challenge 2019题解

    传送门 \(Maximum\ Remaining\) 对于两个数\(a,b\),如果\(a=b\)没贡献,所以不妨假设\(a<b\),有\(a\%b=a\),而\(b\%a<a\).综上, ...

  7. 【code block】局部代码块+构造代码块+静态代码块

    1.局部代码块 位置:位于类的方法中 表示方法:{} 作用:控制变量的生命周期,减少内存消耗 demo: public class LocalCode { public static void mai ...

  8. 【hdu 6172】Array Challenge(数列、找规律)

    多校10 1002 HDU 6172 Array Challenge 题意 There's an array that is generated by following rule. \(h_0=2, ...

  9. 【Code::Blocks】windows 环境下编译 Code::Blocks(已修正)

    Code::Blocks 在2012-11-25发布了最新的12.11版本,相比上一个版本(10.05),Code::Blocks 进行了许多改进和更新(Change log). 引用 Wikiped ...

随机推荐

  1. [Oracle]如何观察Table 的各种Lock 之间的冲突

    [Oracle]如何观察Table 的各种Lock 之间的冲突 举例: Session#15 创建表: SID 15==============create table t1 (c1 number)p ...

  2. MySQL高可用方案MHA在线切换的步骤及原理

    在日常工作中,会碰到如下的场景,如mysql数据库升级,主服务器硬件升级等,这个时候就需要将写操作切换到另外一台服务器上,那么如何进行在线切换呢?同时,要求切换过程短,对业务的影响比较小. MHA就提 ...

  3. Zookeeper Ephemeral结点使用心得

    原文地址:https://www.cnblogs.com/linlemo/p/4807178.html 公司里面在拿Zookeeper做命名服务,通过使用ZK,前端只需要根据指定的ZK地址获得相应的资 ...

  4. VC++6.0的使用感想

    VC++6.0是我接触的第一款编程软件,一直以来都是使用这款软件来完成程序的编写,调试,运行.一直以来都是用C语言编写代码.而VC++6.0窗口简洁明了,占用资源少,上手容易,个人表示很喜欢. VC+ ...

  5. 20135323符运锦----LINUX第三次实践:程序破解

    程序破解 一.掌握NOP.JNE.JE.JMP.CMP汇编指令的机器码 ①NOP:NOP指令即"空指令".执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行N ...

  6. JSONObject使用方法详解

    1.JSONObject介绍 JSONObject-lib包是一个beans,collections,maps,java arrays和xml和JSON互相转换的包. 2.下载jar包 http:// ...

  7. OSG 改变窗口大小

    viewer.realize();//需要realize,否则窗口为null osgViewer::GraphicsWindow *pWnd = dynamic_cast<osgViewer:: ...

  8. react 动态获取数据

    如果reander()里面的dom元素是动态获取的,就要将函数放到setSTATE()里面执行

  9. node的经典事件监听

    let fs = require('fs'); let Event = require('events'); let myEvent = new Event(); //注册一个订阅者 A myEven ...

  10. Laravel 5.5 文档 ] 快速入门 —— 安装配置篇

    服务器要求 Laravel 框架对PHP版本和扩展有一定要求,不过这些要求 Laravel Homestead 都已经满足了,不过如果你没有使用 Homestead 的话(那真是一件很遗憾的事情),有 ...