双log做法,TLE最后一个点求卡常
查看原帖
双log做法,TLE最后一个点求卡常
589961
steambird楼主2024/11/13 21:38

模拟赛的赛时代码,所以可能有点丑陋

#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;
}
2024/11/13 21:38
加载中...