• 保护


    保护

    给出一棵树,若干条树上路径。若干次询问某一点到根的路径上,被覆盖次数大于等于k的点的最浅深度。

    把lca标记打到x点和y点的深度线段树上,那么从下往上线段树合并即可。当然,用主席树从上往下合并也可。

    #include <cstdio>
    #include <vector>
    using namespace std;
    
    const int maxn=2e5+5;
    int n, m, Q;
    int fir[maxn], cnte;
    struct Edge{
    	int to, nxt;
    }e[maxn*2];
    void addedge(int x, int y){
    	Edge &ed=e[++cnte];
    	ed.to=y; ed.nxt=fir[x]; fir[x]=cnte; }
    
    int euler[maxn*2], ftim[maxn], tim, st[maxn*2][20], dep[maxn];
    void predfs(int u, int p){ int v;
    	ftim[u]=tim; euler[tim++]=u; dep[u]=dep[p]+1;
    	for (int i=fir[u]; i; i=e[i].nxt){
    		if ((v=e[i].to)==p) continue;
    		predfs(v, u); euler[tim++]=u; }
    }
    
    int lca(int x, int y){
    	x=ftim[x]; y=ftim[y];
    	if (x>y) swap(x, y); int c=-1;
    	for (int l=y-x+1; l; l>>=1) ++c;  //这里求的是l是2的几次 
    	if (dep[st[x][c]]<dep[st[y-(1<<c)+1][c]]) return st[x][c];
    	else return st[y-(1<<c)+1][c];
    }
    
    int cntn, rt[maxn*2*20], lc[maxn*2*20], rc[maxn*2*20], seg[maxn*2*20];
    void ins(int &x, int l, int r, int p){
    	if (!x) x=++cntn; ++seg[x]; 
    	if (l==r) return; int mid=(l+r)>>1; 
    	if (mid>=p) ins(lc[x], l, mid, p);
    	else ins(rc[x], mid+1, r, p);
    }
    
    int merge(int x, int y){  //把y合并到x上 
    	//最底层的点是代表x和y最底层的和的 然后可以归纳法证明 
    	if (!x) return y; if (!y) return x;
    	seg[x]+=seg[y];
    	lc[x]=merge(lc[x], lc[y]); 
    	rc[x]=merge(rc[x], rc[y]);
    	return x;
    }
    
    int query(int x, int l, int r, int k){
    	if (l==r) return l; int mid=(l+r)>>1;
    	if (seg[lc[x]]>=k) return query(lc[x], l, mid, k);
    	else return query(rc[x], mid+1, r, k-seg[lc[x]]);
    }
    
    vector<int> q[maxn], id[maxn]; int ans[maxn];
    void dfs(int u, int p){ int v;
    	for (int j=fir[u]; j; j=e[j].nxt){
    		if ((v=e[j].to)==p) continue;
    		dfs(v, u); merge(rt[u], rt[v]);
    	}
    	for (int i=0; i<q[u].size(); ++i)
    		ans[id[u][i]]=dep[u]-query(rt[u], 1, n, q[u][i]);
    }
    
    int main(){
    	scanf("%d%d", &n, &m); int x, y, Lca;
    	for (int i=1; i<n; ++i){
    		scanf("%d%d", &x, &y);
    		addedge(x, y); addedge(y, x); }
    	dep[1]=1; predfs(1, 0); dep[0]=1e9;
    	for (int i=0; i<tim; ++i) st[i][0]=euler[i];
    	for (int i=1; i<20; ++i)
    		for (int j=0; j<tim; ++j)
    			if (dep[st[j][i-1]]<dep[st[j+(1<<i-1)][i-1]])
    				st[j][i]=st[j][i-1]; 
    			else st[j][i]=st[j+(1<<i-1)][i-1];
    	for (int i=1; i<=n; ++i) rt[++cntn]=i;
    	for (int i=1; i<=m; ++i){
    		scanf("%d%d", &x, &y); Lca=lca(x, y);
    		ins(rt[x], 1, n, dep[Lca]); ins(rt[y], 1, n, dep[Lca]);
    	}
    	scanf("%d", &Q);
    	for (int i=1; i<=Q; ++i){
    		scanf("%d%d", &x, &y); 
    		q[x].push_back(y); id[x].push_back(i); }
    	dfs(1, 0);
    	for (int i=1; i<=Q; ++i) printf("%d
    ", ans[i]<0?0:ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Redmine-java-api使用
    Junit4 基于 custom Rule retry
    Extentreports在安卓中的应用
    uiautomator 2.0 自定义testrunner使用
    uiautomator 启动原理
    uiautomator 自定义注解的应用
    uiautomator 原理 (UiAutomation、UiAutomatorBridge、QueryController)
    uiautomator 自定义testrunner使用和启动原理
    HeadFirstPython-文件与异常
    HeadFirstPython-初识python
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/9635341.html
Copyright © 2020-2023  润新知