• 『MdOI R1』Treequery


    我们可以思考怎么做呢。
    首先我们需要进行一些分类讨论:
    我们先思考一下如果所有关键点都在 (p) 的子树内,
    那显然是所有关键点的 (Lca)(p) 距离。
    如果所有关键点一些在 (p) 的子树里,一些在子树外,则答案显然为 (0)
    那我们只需要接着讨论一下所有关键点在都在子树外的情况即可。
    我们知道一个点一定会沿着祖先往下走,然后在往一个子树进入。
    如果关键点全都是在祖先的一个子树内,那答案一定是这些关键点的 (Lca)(p) 的距离。
    否则这个答案一定是到祖先的链上的某个点,这个点满足是这个子树里有关键点且是最深的点。
    区间 (Lca) 可以使用线段树解决,然后我们在 (dfn) 序上做一个主席树的操作,然后就可以查询子树内的点的情况了。

    // code by fhq_treap
    #include<bits/stdc++.h>
    #define ll int
    #define N 300005
    
    inline ll read(){
        char C=getchar();
        ll A=0 , F=1;
        while(('0' > C || C > '9') && (C != '-')) C=getchar();
        if(C == '-') F=-1 , C=getchar();
        while('0' <= C && C <= '9') A=(A << 1)+(A << 3)+(C - 48) , C=getchar();
        return A*F;
    }
    
    template <typename T>
    void write(T x)
    {
        if(x < 0) {
            putchar('-');
            x = -x;
        }
        if(x > 9)
            write(x/10);
        putchar(x % 10 + '0');
        return;
    }
    
    ll n,q;
    ll head[N],cnt;
    struct P{
    	int to,next,w;
    }e[N << 1];
    inline void add(int x,int y,int w){
    e[++cnt].to = y,e[cnt].next = head[x],e[cnt].w = w,head[x] = cnt;
    }
    
    //tree
    
    ll dfn[N],s[N],inv[N];
    ll dfncnt;
    int fa[N][30],dep[N],end[N];
    inline void dfs(int x,int f){
    	end[x] = dfn[x] = ++dfncnt;
    	dep[x] = dep[f] + 1;
    	inv[dfncnt] = x;
    	fa[x][0] = f;
    	for(int i = 1;i < 30;i ++)
    	fa[x][i] = fa[fa[x][i - 1]][i - 1];
    	for(int i = head[x];i;i = e[i].next){
    		int v = e[i].to;
    		if(v == f)continue;
    		s[v] = s[x] + e[i].w;
    		dfs(v,x);
    		end[x] = std::max(end[x],end[v]);
    	}
    }
    
    inline ll lca(ll x,ll y){
    	if(dep[y] > dep[x])
    	std::swap(x,y);
    	for(int i = 29;i >= 0;--i){
    		if(dep[fa[x][i]] >= dep[y])
    		x = fa[x][i];
    	}
    	if(x == y)
    	return x;
    	for(int i = 29;i >= 0;--i){
    		if(fa[x][i] != fa[y][i])
    		x = fa[x][i],y = fa[y][i];
    	}
    	return fa[x][0];
    }
    
    ll T[N << 2];
    
    #define ls(x) (x << 1)
    #define rs(x) (x << 1 | 1)
    #define mid ((l + r) >> 1)
    #define root 1,1,n
    
    inline void build(int u,int l,int r){
    	if(l == r){
    		T[u] = l;·1全额日图与i哦怕【-】
    		return ;
    	}
    	build(ls(u),l,mid);
    	build(rs(u),mid + 1,r);
    	T[u] = lca(T[ls(u)],T[rs(u)]);
    	return ;
    }
    
    inline ll qlca(int u,int l,int r,int tl,int tr){
    	if(tl <= l && r <= tr)
    	return T[u];
    	ll li,ri;li = ri = 0;
    	if(tl <= mid)
    	li = qlca(ls(u),l,mid,tl,tr);
    	if(tr > mid)
    	ri = qlca(rs(u),mid + 1,r,tl,tr);
    	return (li && ri) ? lca(li,ri) : li + ri;
    }
    
    //dfn_lca
    
    int H[N * 40];
    int Hcnt;
    int Head[N],Ls[N * 40],Rs[N * 40];
    inline void merge(int las,int &now,int p,int l,int r){
    	if(!now)now = ++Hcnt;
    	Ls[now] = Ls[las];
    	Rs[now] = Rs[las];
    	H[now] = H[las] + 1;
    	if(l == r)
    	return ;
    	if(p <= mid){
    		Ls[now] = 0;
    		merge(Ls[las],Ls[now],p,l,mid);
    	}
    	if(p > mid){
    		Rs[now] = 0;
    		merge(Rs[las],Rs[now],p,mid + 1,r);
    	}
    }
    
    inline ll find(int las,int now,int l,int r,int tl,int tr){
    	if(tl <= l && r <= tr)
    	return H[now] - H[las];
    	ll ans = 0;
    	if(tl <= mid)
    	ans += find(Ls[las],Ls[now],l,mid,tl,tr);
    	if(tr > mid)
    	ans += find(Rs[las],Rs[now],mid + 1,r,tl,tr);
    	return ans;
    }
    
    //主席树
    
    ll las = 0;
    
    inline void solve(ll now,ll l,ll r){
    	ll num = find(Head[dfn[now] - 1],Head[end[now]],1,n,l,r);
    	if(num == (r - l + 1)){
    		las = s[qlca(root,l,r)] - s[now];
    		std::cout<<las<<std::endl;
    	}else{
    		if(num != 0){
    			std::cout<<(las = 0)<<std::endl;
    			return ;
    		}
    		ll x = now;
    		for(int i = 29;i >= 0;--i){
    			int p = fa[x][i];
    			if(p != 0){
    				if(!(find(Head[dfn[p] - 1],Head[end[p]],1,n,l,r)))
    				x = fa[x][i];
    			}
    		}
    		if(fa[x][0] != 0 && !(find(Head[dfn[fa[x][0]] - 1],Head[end[fa[x][0]]],1,n,l,r)))
    		x = fa[x][0];
    		x = fa[x][0];
    		ll L1 = qlca(root,l,r);ll L2 = lca(now,L1);
    		if(L1 == L2)
    		las = s[now] - s[x];
    		else
    		las = s[now] - 2 * s[L2] + s[L1];
    		std::cout<<las<<std::endl;
    		return ;
    	}
    }
    
    int main(){
    	scanf("%d%d",&n,&q);
    	for(int i = 1;i < n;++i){
    		ll x,y,w;
    		scanf("%d%d%d",&x,&y,&w);
    		add(x,y,w);
    		add(y,x,w);
    	}
    	dfs(1,0);
    	build(root);
    	for(int i = 1;i <= n;++i)
    		merge(Head[i - 1],Head[i],inv[i],1,n);
    	while(q -- ){
    		ll p,l,r;
    		scanf("%d%d%d",&p,&l,&r);
    		p ^= las;
    		l ^= las;
    		r ^= las;
    		solve(p,l,r);
    	}
    }
    
    
    
  • 相关阅读:
    Jquery 图片预览插件 imgPreview
    对request.getSession(false)的理解(附程序员常疏忽的一个漏洞)
    JavaScript拖拽实现(附注释),最经典!最简单!短小精悍!
    如何使用VC++写一个小程序来检测.NetFrameWork版本
    利用TreeView实现C#工具箱效果
    JavaScript中json对象和string对象之间的转化
    Ubuntu Server上搭建可用于生产环境的ASP.NET服务器
    winexec()函数的参数说明(c++)
    C#对文件夹的判断、创建、移动、删除
    C#程序不用安装.NET环境运行(让C#程序脱离.net框架)
  • 原文地址:https://www.cnblogs.com/dixiao/p/15321137.html
Copyright © 2020-2023  润新知