• [省选联考 2021 A/B 卷] 宝石


    不妨先研究部分分,观察到有链的部分,于是我们可以很容易想到可以维护出一个每一个点的下一个能成功匹配位置的数组,然后为这个数组再维护一个倍增。

    很容易地想到可以将这个想法搬迁到树上。但是对于每一个询问的维护的路径是很复杂的,不妨离线下来点分治。

    考虑点分治的时候处理两种倍增数组,维护成功匹配若干个的位置。

    然后再 dp 下去,可以在 dp 到某个点的时候计算出它往上到根节点,以每种位置为终点最多可以往前匹配多少步,然后我们就可以在终点处二分统计答案。

    复杂度(O(n (log_{2}^n)^2 + q log_{2}^n))

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define pii pair <int , int>
    #define mp make_pair
    #define fs first
    #define sc second
    using namespace std;
    typedef long long LL;
    
    template <typename T>
    void read(T &x) {
    	T f=1;x=0;char s=getchar();
    	while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
    	while(s>='0'&&s<='9') {x=(x<<3)+(x<<1)+(s^'0');s=getchar();}
    	x *= f;
    }
    
    template <typename T>
    void write(T x , char s='
    ') {
    	if(!x) {putchar('0');putchar(s);return;}
    	if(x<0) {putchar('-');putchar(s);return;}
    	int tmp[25] = {} , t = 0;
    	while(x) tmp[t ++] = x % 10 , x /= 10;
    	while(t -- > 0) putchar(tmp[t] + '0');
    	putchar(s);
    }
    
    const int MAXN = 2e5 + 5;
    
    int n , m , c;
    int P[MAXN] , pos[MAXN] , w[MAXN];
    int head[MAXN] , to[MAXN << 1] , nxt[MAXN << 1] , cnt;
    void add(int u , int v) {nxt[++cnt] = head[u];head[u] = cnt;to[cnt] = v;}
    
    int ans[MAXN] , Q;
    
    vector <pii> q[MAXN];
    
    int siz[MAXN] , rt , mx , vis[MAXN];
    
    void get_siz(int x , int fa) {
    	siz[x] = 1;
    	for (int i = head[x]; i; i = nxt[i]) {
    		int v = to[i];
    		if(v == fa || vis[v]) continue;
    		get_siz(v , x);
    		siz[x] += siz[v];
    	}
    }
    
    void get_root(int x , int fa , int num) {
    	int cur = 0;
    	for (int i = head[x]; i; i = nxt[i]) {
    		int v = to[i];
    		if(v == fa || vis[v]) continue;
    		get_root(v , x , num);
    		if(siz[v] > cur) cur = siz[v]; 
    	}
    	if(num - siz[x] > cur) cur = num - siz[x];
    	if(cur < mx) mx = cur , rt = x;
    }
    
    int cop[MAXN] , id[MAXN];
    int f1[MAXN][22] , f2[MAXN][22] , dp[MAXN];
    
    void dfs(int x , int fa , int I) {
    	id[x] = I;
    	int tmp = cop[pos[w[x]]];
    	if(pos[w[x]]) {
    		cop[pos[w[x]]] = x;
    		f2[x][0] = cop[pos[w[x]] + 1];
    		for (int i = 1; i <= 20; ++i) f2[x][i] = f2[f2[x][i - 1]][i - 1];
    	}
    	f1[x][0] = cop[1];
    	for (int i = 1; i <= 20; ++i) f1[x][i] = f2[f1[x][i - 1]][i - 1];
    	for (int i = head[x]; i; i = nxt[i]) {
    		int v = to[i];
    		if(v == fa || vis[v]) continue;
    		dfs(v , x , I);
    	}
    	cop[pos[w[x]]] = tmp;
    }
    
    int get_val(int x) {
    	int res = 0;
    	for (int i = 20; i >= 0; --i) {
    		if(f1[x][i]) {
    			res += (1 << i);
    			x = f1[x][i];
    			break;
    		}
    	}
    	if(!res) return res;
    	for (int i = 20; i >= 0; --i) {
    		if(f2[x][i]) {
    			res += (1 << i);
    			x = f2[x][i];
    		}
    	}
    	return res;
    }
    
    void cal(int x , int fa) {
    	int tmp = dp[pos[w[x]]];
    	if(pos[w[x]] && !vis[x]) dp[pos[w[x]]] = max(dp[pos[w[x]]] , dp[pos[w[x]] - 1] + 1);
    	for (int i = 0; i < (int)q[x].size(); ++i) {
    		int s = q[x][i].fs , p = q[x][i].sc;
    		if(id[s] == id[x] || !id[s] || !id[x]) continue;
    		ans[p] = get_val(s);
    		int cur = ans[p];
    		int l = cur , r = c;
    		while(l <= r) {
    			int mid = (l + r) >> 1;
    			if(dp[mid] + cur >= mid) l = mid + 1 , ans[p] = mid;
    			else r = mid - 1;
    		}
    	}
    	for (int i = head[x]; i; i = nxt[i]) {
    		int v = to[i];
    		if(v == fa || vis[v]) continue;
    		cal(v , x);
    	}
    	dp[pos[w[x]]] = tmp;
    }
    
    void clr(int x , int fa) {
    	id[x] = cop[pos[w[x]]] = dp[pos[w[x]]] = 0;
    	for (int i = 0; i <= 20; ++i) f1[x][i] = f2[x][i] = 0;
    	for (int i = head[x]; i; i = nxt[i]) {
    		int v = to[i];
    		if(v == fa || vis[v]) continue;
    		clr(v , x);
    	}
    }
    
    void work(int x) {
    	get_siz(x , 0);
    	rt = mx = 1e9;
    	get_root(x , 0 , siz[x]);
    	x = rt;
    	vis[x] = 1;
    	cop[pos[w[x]]] = x;
    	int num = 0;
    	for (int i = head[x]; i; i = nxt[i]) {
    		int v = to[i];
    		if(vis[v]) continue;
    		dfs(v , x , ++num);
    	}
    	id[x] = ++num;
    	cal(x , x);
    	clr(x , x);
    	for (int i = head[x]; i; i = nxt[i]) {
    		int v = to[i];
    		if(vis[v]) continue;
    		work(v);
    	}
    }
    
    int main() {
    	freopen("gem.in" , "r" , stdin);
    	freopen("gem.out" , "w" , stdout);
    	read(n),read(m),read(c);
    	for (int i = 1; i <= c; ++i) read(P[i]) , pos[P[i]] = i;
    	for (int i = 1; i <= n; ++i) read(w[i]);
    	for (int i = 1; i < n; ++i) {
    		int u , v;
    		read(u),read(v);
    		add(u , v) , add(v , u);
    	}
    	read(Q);
    	for (int i = 1; i <= Q; ++i) {
    		int s , t;
    		read(s),read(t);
    		q[t].push_back(mp(s , i));
    	}
    	work(1);
    	for (int i = 1; i <= Q; ++i) write(ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    面对缓存,有哪些问题需要思考?
    .NET 文件格式相关开源项目
    (转)谈谈用ASP.NET开发的大型网站有哪些架构方式(成本)
    (转)基于微软平台IIS/ASP.NET开发的大型网站有哪些?
    sql查询优化策略
    初入linux系统
    Npoi操作Excel
    List GroupBy真实用法,Reflection(反射)用法,Enum用法,正则,搜索下拉布局
    3.2.2.4 文本匹配锚点
    3.2.2.3 单个表达式匹配多字符
  • 原文地址:https://www.cnblogs.com/Reanap/p/14648353.html
Copyright © 2020-2023  润新知