保护

保护

给出一棵树,若干条树上路径。若干次询问某一点到根的路径上,被覆盖次数大于等于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\n", ans[i]<0?0:ans[i]);
	return 0;
}
posted @ 2018-09-12 16:03  pechpo  阅读(162)  评论(0编辑  收藏  举报