小清新点分治求条!!!
查看原帖
小清新点分治求条!!!
1063631
Bacterium2楼主2025/1/21 20:55

小清新点分治代码求条!小样例拍不出,但是大洋里输出0的时候几乎都不对 马蜂良好

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <vector>
#include <cassert>
using namespace std;

inline long long read() {
	long long num = 0, fg = 1;
	char c = getchar();
	while(!isdigit(c)) {
		if (c =='-') fg = -fg;
		c = getchar();
	}
	while(isdigit(c)) {
		num = num * 10 + c - '0';
		c = getchar();
	}
	return num * fg;
}

int n, m, c;

static const int inf = 0x3f3f3f3f;
static const int MAXN = 200005;
static const int MAXC = 50005;

int Q = 0;
struct Query {
	int s, t;
	int id;
};
Query q[MAXN];

int P[MAXN];
int w[MAXN];

int tmp[MAXN];
void sortp();

int head[MAXN];
int vert[MAXN];
int Next[MAXN];
int tot = 0;
void Link(int, int);

namespace Acc {
	int solve();
}

#define DEBUG_ARRAY(ARR, LIM)		\
	printf(#ARR "[]:\n");			\
	for (int i = 1; i <= LIM; i++)	\
		printf("%d ", ARR[i]);		\
	printf("\n");

int main() {
	// 读入 
	n = read(), m = read(), c = read();
	
	for (int i = 1; i <= c; i++) P[i] = read();
	for (int i = 1; i <= n; i++) w[i] = read();
	
	sortp();
	
	for (int i = 1; i <= n - 1; i++) {
		int x = read(), y = read();
		Link(x, y);
		Link(y, x);
	}
	
	Q = read();
	
	for (int i = 1; i <= Q; i++) {
		int s = read(), t = read();
		q[i].s = s, q[i].t = t;
		q[i].id = i;
	}
	
	// solve 
	Acc::solve();
	return 0;
}

namespace Acc {
	
	struct Segmt {
		static const int SIZE = MAXN << 2;
		struct SegmtNode {
			int mx;
			SegmtNode(): mx(0) { }
		};
		SegmtNode t[SIZE];
		
		void pushup(int p) {
			t[p].mx = max(t[p << 1].mx, t[p << 1 | 1].mx);
		}
		
		void modify(int pos, int dat, int l, int r, int p) {
			if (l == r) {
				t[p].mx = dat;
				return ;
			}
			
			int mid = (l + r) >> 1;
			
			if (pos <= mid) modify(pos, dat, l, mid, p << 1);
			else modify(pos, dat, mid + 1, r, p << 1 | 1);
			pushup(p);
		}
		
		void insert(int pos, int dat, int l, int r, int p) {
			if (l == r) {
				t[p].mx = max(t[p].mx, dat);
				return ;
			}
			
			int mid = (l + r) >> 1;
			
			if (pos <= mid) insert(pos, dat, l, mid, p << 1);
			else insert(pos, dat, mid + 1, r, p << 1 | 1);
			pushup(p);
		}
		
		int getmax(int nl, int nr, int l, int r, int p) {
			if (nl == l && nr == r) {
				return t[p].mx;
			}
			
			int mid = (l + r) >> 1;
			if (nr <= mid) return getmax(nl, nr, l, mid, p << 1);
			if (mid < nl) return getmax(nl, nr, mid + 1, r, p << 1 | 1);
			return max(
				getmax(nl, mid, l, mid, p << 1),
				getmax(mid + 1, nr, mid + 1, r, p << 1 | 1)
			);
		}
		
		int getval(int pos, int l, int r, int p) {
			if (l == r) return t[p].mx;
			
			int mid = (l + r) >> 1;
			if (pos <= mid) return getval(pos, l, mid, p << 1);
			return getval(pos, mid + 1, r, p << 1 | 1);
		}
	};
	
	struct Stack {
		int data[MAXN];
		int top;
		
		void push(int x) {
			this->data[++this->top] = x;
		}
		int pop() {
			return this->data[this->top--];
		}
		int get() {
			return this->data[this->top];
		}
		int size() {
			return this->top;
		}
		bool empty() {
			return this->top == 0;
		}
		void clear() {
			this->top = 0;
		}
		Stack(): top(0) { }
		
		int &operator[](int index) {
			return this->data[index];
		}
	};
	
	int Root = 0;
	int Tsiz = 0;
	int siz[MAXN];
	int mt[MAXN];
	void GetRoot(int, int);
	
	vector < int > qa[MAXN];
	vector < int > qb[MAXN];
	
	int vis[MAXN];
	void work(int, int);
	
	int apr[MAXN];
	int tim = 0;
	void dfs(int, int);
	
	// col1 左半边的宝石数
	// col2 答案 
	int col1[MAXN];
	int col2[MAXN];
	
	int pre[MAXN];
	int num[MAXN];
	
	int solve() {
		
		for (int i = 1; i <= Q; i++) {
			int s = q[i].s, t = q[i].t;
			qa[s].push_back(i);
			qb[t].push_back(i);
		}
		
		Tsiz = n;
		Root = 0;
		mt[Root] = inf;
		GetRoot(1, 0);
		GetRoot(Root, 0);
		
		work(Root, 0);
		
		for (int i = 1; i <= Q; i++) {
			if (q[i].s == q[i].t) {
				if (w[q[i].s] == 1) col2[i] = 1;
				else col2[i] = 0;
			}
		}
		
		for (int i = 1; i <= Q; i++) {
			printf("%d\n", col2[i]);
		}
		
		return 0;
	}
	
	Stack q1;
	
	int rem[MAXN];
	int rtot = 0;
	
	// 求 col1 
	void dfs1(int x, int fa) {
		
		num[x] = w[x];
		int lst = pre[w[x]];
		pre[w[x]] = x;
		num[x] = max(num[x], num[pre[w[x] + 1]]);
		
		for (int i = head[x]; i; i = Next[i]) {
			int y = vert[i];
			if (y == fa || vis[y]) continue;
			dfs1(y, x);
		}
		
		for (vector<int>::iterator it = qa[x].begin(); it != qa[x].end(); it++) {
			int qid = *it;
			q1.push(qid);
			apr[qid] = tim;
		}
		
		if (w[x] == 1) {
			while(!q1.empty()) {
				int u = q1.pop();
				col1[u] = num[x];
				rem[++rtot] = u;
			}
		}
		
		pre[w[x]] = lst;
	}
	
	Segmt t;
	
	// 求 col2
	 
	void dfs2(int x, int fa) {
		
		num[x] = w[x];
		int lstpos = pre[w[x]];
		pre[w[x]] = x;
		if (num[pre[w[x] - 1]]) num[x] = min(num[x], num[pre[w[x] - 1]]);
		else num[x] = w[x];
		
		int lstcol = t.getval(num[x], 1, n, 1);
		
		t.insert(num[x], w[x], 1, n, 1);
		
		for (vector<int>::iterator it = qb[x].begin(); it != qb[x].end(); it++) {
			int qid = *it;
			if (apr[qid] != tim) continue;
			
			int soucol = col1[qid];
			
			int mxval = t.getmax(1, soucol + 1, 1, n, 1);
			
			assert(col2[qid] == 0);
			col2[qid] = max(mxval, col1[qid]);
		}
		
		for (int i = head[x]; i; i = Next[i]) {
			int y = vert[i];
			if (y == fa || vis[y]) continue;
			dfs2(y, x);
		}
		
		t.modify(num[x], lstcol, 1, n, 1);
		pre[w[x]] = lstpos;
	}
	
	Stack nodex;
	
	void work2(int, int);
	
	// 点分治主体函数:
	 
	void work(int x, int fa) {
		
		vis[x] = true;
		
		nodex.clear();
		for (int i = head[x]; i; i = Next[i]) {
			int y = vert[i];
			if (y == fa || vis[y]) continue;
			nodex.push(y);
		}
		
		num[x] = w[x];
		int lstpos = pre[w[x]];
		assert(lstpos == 0);
		num[x] = max(num[x], num[pre[w[x] + 1]]);
		pre[w[x]] = x;
		
		// 由于路径有向,需要 reserve 一次重新做 dfs,所以有 2 个 work2(); 
		work2(x, fa);
		
		int nodex_siz = nodex.size();
		for (int i = 1; i <= nodex_siz / 2; i++) {
			swap(nodex[i], nodex[nodex_siz - i + 1]);
		}
		
		work2(x, fa);
		
		pre[w[x]] = lstpos;
		
		// 终点在 Root 上的询问,答案是左半边处理的宝石总数 
		for (vector<int>::iterator it = qb[x].begin(); it != qb[x].end(); it++) {
			int qid = *it;
			if (apr[qid] != tim) continue;
			
			col2[qid] = col1[qid];
		}
		
		for (int i = head[x]; i; i = Next[i]) {
			int y = vert[i];
			if (y == fa || vis[y]) continue;
			
			Root = 0;
			mt[Root] = inf;
			
			Tsiz = siz[y];
			GetRoot(y, 0);
			GetRoot(Root, 0);
			
			work(Root, 0);
		}
	}
	
	void work2(int x, int fa) {
		tim++;
		if (w[Root] == 1) for (vector<int>::iterator it = qa[Root].begin(); 
		  it != qa[Root].end(); it++) {
			int qid = *it;
			apr[qid] = tim;
			col1[qid] = 1;
			rem[++rtot] = qid;
		}
		
		for (int i = 1; i <= nodex.size(); i++) {
			int y = nodex[i];
			if (y == fa || vis[y]) continue;
			
			// 求 起点在之前子树上的询问,终点在当前子树的 col2[]. 
			dfs2(y, x);
			
			// 求 起点在当前子树的的询问的 col1 
			dfs1(y, x);
			
			if (w[Root] == 1) {
				while(!q1.empty()) {
					int u = q1.pop();
					col1[u] = num[Root];
					rem[++rtot] = u;
				}
			}
			
			q1.clear();
		}
		
		for (int i = 1; i <= rtot; i++) {
			col1[rem[i]] = false;
		}
		rtot = 0;
	}
	
	void GetRoot(int x, int fa) {
		siz[x] = 1;
		mt[x] = 0;
		for (int i = head[x]; i; i = Next[i]) {
			int y = vert[i];
			if (y == fa || vis[y]) continue;
			GetRoot(y, x);
			siz[x] += siz[y];
			mt[x] = max(mt[x], siz[y]);
		}
		mt[x] = max(mt[x], Tsiz - siz[x]);
		if (mt[Root] > mt[x]) Root = x;
		return ;
	}
}

// sortp():: 重新定义 w[] .
void sortp() {
	for (int i = 1; i <= c; i++) tmp[P[i]] = i;
	for (int i = 1; i <= n; i++) w[i] = tmp[w[i]];
}

void Link(int x, int y) {
	vert[++tot] = y;
	Next[tot] = head[x];
	head[x] = tot;
}
/*
7 10 5
1 2 3 4 5 
1 2 3 5 2 4 1 
1 2
1 3
2 4
2 5
3 6
6 7
1
5 4
*/

2025/1/21 20:55
加载中...