steambird @ 2024-11-13 21:38:21
模拟赛的赛时代码,所以可能有点丑陋
#include <bits/stdc++.h>
using namespace std;
inline void train() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
}
inline int maxi(int a, int b) {
return a > b ? a : b;
}
inline int mini(int a, int b) {
return a < b ? a : b;
}
#define lch (root<<1)
#define rch ((root<<1)|1)
#define mids() const int mid = (lrange[root] + rrange[root]) >> 1
#define lcall lch, maxi(lrange[root], l), mini(mid, r)
#define rcall rch, maxi(mid+1, l), mini(rrange[root], r)
constexpr int N = 300004, NS = 2e6+4;
int lrange[NS], rrange[NS];
vector<int> data[NS], rdata[NS];
void build(const int root, const int l, const int r) {
if (l > r) return;
lrange[root] = l; rrange[root] = r;
if (l == r) return;
mids();
build(lch, l, mid); build(rch, mid+1, r);
}
// Maybe it is not guaranteed that values are sorted !!!
// val - Current time when "head" is entered.
void update_pos(const int root, const int l, const int r, const int val, const int top) {
if (l > r) return;
//#ifndef ONLINE_JUDGE
// cerr << "[" << lrange[root] << "," << rrange[root] << "]: Call shallow-to-deep " << l << " to " << r << ", when it was " << val << " at " << top << endl;
//#endif
if (lrange[root] >= l && rrange[root] <= r) {
//#ifndef ONLINE_JUDGE
// assert(lrange[root] >= top);
// cerr << "Positive [" << lrange[root] << "," << rrange[root] << "]: Tagged " << (val + (lrange[root] - top)) << "\n";
//
//#endif
data[root].push_back(val + (lrange[root] - top)); // Therefore, a value will be in at most log n sequences
return;
}
// Since all tags are permanent, we don't have to pass it down.
mids();
update_pos(lcall, val, top); update_pos(rcall, val, top);
// e.g. rrange[lch] = 5, val = 4
}
// When climbing, dfn is from larger to smaller. PLEASE PAY ATTENTION TO
// PARAMETERS HERE !!!
// A special feature is that "head" will be the right bound, rather than left.
// Special evaluation will be needed. Still, "val" is for initial entrance.
void update_neg(const int root, const int l, const int r, const int val, const int top) {
if (l > r) return;
//#ifndef ONLINE_JUDGE
// cerr << "[" << lrange[root] << "," << rrange[root] << "]: Call deep-to-shallow " << l << " to " << r << ", when it was " << val << " at " << top << endl;
//#endif
if (lrange[root] >= l && rrange[root] <= r) {
//#ifndef ONLINE_JUDGE
// assert(top >= rrange[root]);
// cerr << "Negative [" << lrange[root] << "," << rrange[root] << "]: Tagged " << (val + (top - rrange[root])) << "\n";
//
//#endif
rdata[root].push_back(val + (top - rrange[root]));
return;
}
mids();
update_neg(lcall, val, top); update_neg(rcall, val, top);
}
void reconstruct(const int root, const int l, const int r) {
if (l > r) return;
sort(data[root].begin(), data[root].end()); sort(rdata[root].begin(), rdata[root].end());
if (lrange[root] == rrange[root]) return;
mids();
reconstruct(lch, l, mid); reconstruct(rch, mid+1, r);
}
vector<int> tree[N];
int n, m, w[N];
// Must have "&" reference, or TLE
int counting(vector<int> &source, const int target) {
auto lfnd = lower_bound(source.begin(), source.end(), target);
if (lfnd == source.end()) return 0;
if ((*lfnd) != target) return 0;
auto rfnd = upper_bound(source.begin(), source.end(), target);
return (rfnd - lfnd);
}
int sz[N], dfn[N], dpt = 1, hson[N], depth[N], father[N], head[N], rdfn[N];
bool is_heavy[N];
// Demanding w[target]. You should evaluate expected entrance time...
int query(const int root, const int target) {
int ans = 0, actual = rdfn[target];
if (target < lrange[root] || target > rrange[root]) return 0;
const int pos_finding = w[actual] - (target - lrange[root]); // -- w should be 'actual'
ans += counting(data[root], pos_finding);
const int neg_finding = w[actual] - (rrange[root] - target); // -- w should be 'actual'
ans += counting(rdata[root], neg_finding);
//#ifndef ONLINE_JUDGE
// cerr << "[" << lrange[root] << "," << rrange[root] << "]: ";
// cerr << target << " watching time " << w[actual] << " means positive:" << pos_finding << ", negative:" << neg_finding << ". resulted " << ans << endl;
//#endif
if (lrange[root] == rrange[root]) return ans;
mids();
if (target <= mid) {
return ans + query(lch, target);
} else {
return ans + query(rch, target);
}
}
void dfs1(int cur, int fa) {
depth[cur] = depth[fa] + 1;
father[cur] = fa;
sz[cur] = 1;
int msz = 0, mat = 0;
for (auto &i : tree[cur]) {
if (i == fa) continue;
dfs1(i, cur);
sz[cur] += sz[i];
if (sz[i] > msz) {
msz = sz[i]; mat = i;
}
}
hson[cur] = mat; is_heavy[mat] = true;
}
void dfs2(int cur, int fa) {
dfn[cur] = (dpt++); // Xinyoudui dfn is inoperative currently !!
rdfn[dfn[cur]] = cur;
head[cur] = cur;
if (is_heavy[cur] && is_heavy[father[cur]]) head[cur] = head[father[cur]];
if (hson[cur]) dfs2(hson[cur], cur);
for (auto &i : tree[cur]) {
if (i == fa || i == hson[cur]) continue;
dfs2(i, cur);
}
}
struct split_res {
int from, to; // [from] considered head
split_res() {
}
split_res(int from, int to) : from(from), to(to) {
}
};
vector<split_res> spls;
int main() {
train();
cin>>n>>m;
for (int i = 0; i < (n-1); i++) {
int u,v;
cin>>u>>v;
tree[u].push_back(v); tree[v].push_back(u);
}
// Split:
is_heavy[1] = true; // For some reasons...
dfs1(1, 1); dfs2(1, 1);
build(1, 1, n);
//#ifndef ONLINE_JUDGE
// for (int i = 1; i <= n; i++) cerr<<dfn[i]<<' ';
// cerr<<endl;
// for (int i = 1; i <= n; i++) cerr<<hson[i]<<' ';
// cerr<<endl;
//#endif
// cerr << "End of split & build" << endl;
for (int i = 1; i <= n; i++) cin>>w[i];
for (int qs = 0; qs < m; qs++) {
int s, t, stime = 0;
cin>>s>>t;
// cerr << "Considering " << s << " -> " << t << endl;
spls.clear();
int cnt = 0;
while (head[s] != head[t]) {
cnt++;
if (depth[head[s]] > depth[head[t]]) {
// s has negative climber
update_neg(1, dfn[head[s]], dfn[s], stime, dfn[s]);
// cerr << "--------------------------------------\n";
stime += depth[s] - depth[head[s]] + 1;
s = father[head[s]];
} else {
// update_pos(1, dfn[head[t]], dfn[t], ttime, dfn[head[t]]); // You must cache these changes !!!
// ttime += depth[t] - depth[head[t]]; // (Since you don't know former process)
spls.push_back(split_res(head[t], t)); // DFN will be used later, not here.
t = father[head[t]];
}
}
// cerr << "End of unique-father\n";
// In the same chain, feel free to swap:
if (depth[s] > depth[t]) {
// From s to t, negatively climbing
update_neg(1, dfn[t], dfn[s], stime, dfn[s]);
stime += depth[s] - depth[t] + 1;
} else {
// From t to s, positively descending
update_pos(1, dfn[s], dfn[t], stime, dfn[s]);
stime += depth[t] - depth[s] + 1;
}
// cerr << "Begin descending\n";
for (auto it = spls.rbegin(); it != spls.rend(); it++) {
split_res &spl = (*it);
update_pos(1, dfn[spl.from], dfn[spl.to], stime, dfn[spl.from]);
// cerr << "--------------------------------------\n";
stime += depth[spl.to] - depth[spl.from] + 1;
} // End of single processor.
// cerr << "=====================================================\n";
}
reconstruct(1, 1, n);
for (int i = 1; i <= n; i++) {
cout<<query(1, dfn[i])<<' ';
// cerr << endl << endl;
}
cout<<endl;
//cout<<flush;
return 0;
}
by __mt19937__ @ 2025-01-01 16:52:39
@steambird
code :
#include <bits/stdc++.h>
using namespace std;
inline void train() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
}
inline int maxi(register int a, register int b) {
return a > b ? a : b;
}
inline int mini(register int a, register int b) {
return a < b ? a : b;
}
#define lch (root<<1)
#define rch ((root<<1)|1)
#define mids() const int mid = (lrange[root] + rrange[root]) >> 1
#define lcall lch, maxi(lrange[root], l), mini(mid, r)
#define rcall rch, maxi(mid+1, l), mini(rrange[root], r)
constexpr int N = 300004, NS = 2e6+4;
int lrange[NS], rrange[NS];
vector<int> data[NS], rdata[NS];
inline void build(register const int root, register const int l, register const int r) {
if (l > r) return;
lrange[root] = l; rrange[root] = r;
if (l == r) return;
mids();
build(lch, l, mid); build(rch, mid+1, r);
}
// Maybe it is not guaranteed that values are sorted !!!
// val - Current time when "head" is entered.
inline void update_pos(register const int root, register const int l, register const int r, register const int val, register const int top) {
if (l > r) return;
if (lrange[root] >= l && rrange[root] <= r) {
data[root].push_back(val + (lrange[root] - top)); // Therefore, a value will be in at most log n sequences
return;
}
mids();
update_pos(lcall, val, top); update_pos(rcall, val, top);
}
inline void update_neg(register const int root, register const int l, register const int r, register const int val, register const int top) {
if (l > r) return;
if (lrange[root] >= l && rrange[root] <= r) {
rdata[root].push_back(val + (top - rrange[root]));
return;
}
mids();
update_neg(lcall, val, top); update_neg(rcall, val, top);
}
void reconstruct(register const int root, register const int l, register const int r) {
if (l > r) return;
sort(data[root].begin(), data[root].end()); sort(rdata[root].begin(), rdata[root].end());
if (lrange[root] == rrange[root]) return;
mids();
reconstruct(lch, l, mid); reconstruct(rch, mid+1, r);
}
vector<int> tree[N];
int n, m, w[N];
inline int counting(vector<int> &source, register const int target) {
register auto lfnd = lower_bound(source.begin(), source.end(), target);
if (lfnd == source.end()) return 0;
if ((*lfnd) != target) return 0;
register auto rfnd = upper_bound(source.begin(), source.end(), target);
return (rfnd - lfnd);
}
int sz[N], dfn[N], dpt = 1, hson[N], depth[N], father[N], head[N], rdfn[N];
bool is_heavy[N];
inline int query(register const int root, register const int target) {
register int ans = 0, actual = rdfn[target];
if (target < lrange[root] || target > rrange[root]) return 0;
register const int pos_finding = w[actual] - (target - lrange[root]); // -- w should be 'actual'
ans += counting(data[root], pos_finding);
register const int neg_finding = w[actual] - (rrange[root] - target); // -- w should be 'actual'
ans += counting(rdata[root], neg_finding);
//#ifndef ONLINE_JUDGE
// cerr << "[" << lrange[root] << "," << rrange[root] << "]: ";
// cerr << target << " watching time " << w[actual] << " means positive:" << pos_finding << ", negative:" << neg_finding << ". resulted " << ans << endl;
//#endif
if (lrange[root] == rrange[root]) return ans;
mids();
if (target <= mid) {
return ans + query(lch, target);
} else {
return ans + query(rch, target);
}
}
void dfs1(register const int cur, register const int fa) {
depth[cur] = depth[fa] + 1;
father[cur] = fa;
sz[cur] = 1;
register int msz = 0, mat = 0;
for (register auto &i : tree[cur]) {
if (i == fa) continue;
dfs1(i, cur);
sz[cur] += sz[i];
if (sz[i] > msz) {
msz = sz[i]; mat = i;
}
}
hson[cur] = mat; is_heavy[mat] = true;
}
void dfs2(register const int cur, register const int fa) {
dfn[cur] = (dpt++); // Xinyoudui dfn is inoperative currently !!
rdfn[dfn[cur]] = cur;
head[cur] = cur;
if (is_heavy[cur] && is_heavy[father[cur]]) head[cur] = head[father[cur]];
if (hson[cur]) dfs2(hson[cur], cur);
for (register auto &i : tree[cur]) {
if (i == fa || i == hson[cur]) continue;
dfs2(i, cur);
}
}
struct split_res {
int from, to; // [from] considered head
split_res() {
}
split_res(int from, int to) : from(from), to(to) {
}
};
vector<split_res> spls;
int main() {
train();
cin>>n>>m;
for (register int i = 0; i < (n-1); i++) {
register int u,v;
cin>>u>>v;
tree[u].push_back(v); tree[v].push_back(u);
}
is_heavy[1] = true;
dfs1(1, 1); dfs2(1, 1);
build(1, 1, n);
for (register int i = 1; i <= n; i++) cin>>w[i];
for (register int qs = 0; qs < m; qs++) {
register int s, t, stime = 0;
cin>>s>>t;
spls.clear();
register int cnt = 0;
while (head[s] != head[t]) {
cnt++;
if (depth[head[s]] > depth[head[t]]) {
update_neg(1, dfn[head[s]], dfn[s], stime, dfn[s]);
stime += depth[s] - depth[head[s]] + 1;
s = father[head[s]];
} else { // (Since you don't know former process)
spls.push_back(split_res(head[t], t)); // DFN will be used later, not here.
t = father[head[t]];
}
}
if (depth[s] > depth[t]) {
update_neg(1, dfn[t], dfn[s], stime, dfn[s]);
stime += depth[s] - depth[t] + 1;
} else {
update_pos(1, dfn[s], dfn[t], stime, dfn[s]);
stime += depth[t] - depth[s] + 1;
}
for (register auto it = spls.rbegin(); it != spls.rend(); it++) {
split_res &spl = (*it);
update_pos(1, dfn[spl.from], dfn[spl.to], stime, dfn[spl.from]);
stime += depth[spl.to] - depth[spl.from] + 1;
}
}
reconstruct(1, 1, n);
for (register int i = 1; i <= n; i++) {
cout<<query(1, dfn[i])<<' ';
}
cout<<endl;
return 0;
}
过了
by __mt19937__ @ 2025-01-01 16:53:25
记录