zoukankan      html  css  js  c++  java
  • 洛谷 P6071 『MdOI R1』Treequery(LCA+线段树+主席树)

    题目链接

    题意:给出一棵树,有边权,(m) 次询问,每次给出三个数 (p,l,r),求边集 (igcaplimits_{i=l}^rE(p,i)) 中所有边的权值和。
    其中 (E(u,v)) 为点 (u) 到点 (v) 的路径中经过的边的集合。
    强制在线。
    (1 leq n leq 2 imes 10^5)

    果然是神仙 ix35 wdl 出的题啊……
    不妨以 (1) 为根,做一遍 dfs 求出它们的 dfs 序,以及它们到根的距离 (d_i)
    每次询问,我们求出 (l,l+1,dots,r) 中所有点的 LCA,假设为 (t)
    我们将 ([l,r]) 中的点分成三个集合:

    • 集合 A:在 (p) 的子树中。
    • 集合 B:不在 (p) 的子树中,但是与 (p) 在根节点的同一子树中。
    • 集合 C:与 (p) 在根节点的不同子树中。
      接下来就是分情况讨论了:
    1. 如果所有点都属于集合 A,那么答案就是 (d_t-d_p)
    2. 如果有的点都属于集合 A,有的点不属于集合 A,那么答案为 (0)
    3. 如果没有点属于集合 A,那么从 (p) 不断地往上跳,直到 ([l,r]) 中至少有一个点在当前点的子树内,记当前所在的点为 (f),那么又有两种情况:
    • (f)(t) 上方,那么答案为 (d_p+d_t-2 imes d_f)
    • (f)(t) 下方,那么答案为 (d_p-d_f)
      口胡完了,实现也不难:
    • 求区间 LCA,建一棵线段树,节点上维护 LCA。
    • 判断有多少个点在 (x) 的子树中:注意到 (x) 子树的 dfs 序是一个连续的区间,可以想到主席树。以 dfs 序为节点下标建一棵主席树。第 (i) 棵树的第 (j) 个位置上的数表示节点 (1) 到节点 (i) 中有多少个点的 dfs 序为 (j)
    • 往上跳:倍增
    //Coded by tzc_wk
    /*
    数据不清空,爆零两行泪。
    多测不读完,爆零两行泪。
    边界不特判,爆零两行泪。
    贪心不证明,爆零两行泪。
    D P 顺序错,爆零两行泪。
    大小少等号,爆零两行泪。
    变量不统一,爆零两行泪。
    越界不判断,爆零两行泪。
    调试不注释,爆零两行泪。
    溢出不 l l,爆零两行泪。
    忘文件操作,爆零两行泪。
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define fi			first
    #define se			second
    #define fz(i,a,b)	for(int i=a;i<=b;i++)
    #define fd(i,a,b)	for(int i=a;i>=b;i--)
    #define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
    #define all(a)		a.begin(),a.end()
    #define giveup(...) return printf(__VA_ARGS__),0;
    #define fill0(a)	memset(a,0,sizeof(a))
    #define fill1(a)	memset(a,-1,sizeof(a))
    #define fillbig(a)	memset(a,0x3f,sizeof(a))
    #define fillsmall(a) memset(a,0xcf,sizeof(a))
    #define mask(a)		(1ll<<(a))
    #define maskx(a,x)	((a)<<(x))
    #define _bit(a,x)	(((a)>>(x))&1)
    #define _sz(a)		((int)(a).size())
    #define filei(a)	freopen(a,"r",stdin);
    #define fileo(a)	freopen(a,"w",stdout);
    #define fileio(a) 	freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    #define eprintf(...) fprintf(stderr,__VA_ARGS__)
    #define put(x)		putchar(x)
    #define eoln        put('
    ')
    #define space		put(' ')
    #define y1			y_chenxiaoyan_1
    #define y0			y_chenxiaoyan_0
    //#define int long long
    typedef pair<int,int> pii;
    inline int read(){
    	int x=0,neg=1;char c=getchar();
    	while(!isdigit(c)){
    		if(c=='-')	neg=-1;
    		c=getchar();
    	}
    	while(isdigit(c))	x=x*10+c-'0',c=getchar();
    	return x*neg;
    }
    inline void print(int x){
    	if(x<0){
    		putchar('-');
    		print(abs(x));
    		return;
    	}
    	if(x<=9)	putchar(x+'0');
    	else{
    		print(x/10);
    		putchar(x%10+'0');
    	}
    }
    inline int qpow(int x,int e,int _MOD){
    	int ans=1;
    	while(e){
    		if(e&1)	ans=ans*x%_MOD;
    		x=x*x%_MOD;
    		e>>=1;
    	}
    	return ans;
    }
    int n=read(),m=read();
    struct edge{
    	int u,v,w;
    	edge(){/*Problemsetter of P6071 AK IOI*/}
    	edge(int _u,int _v,int _w){
    		u=_u;v=_v;w=_w;
    	}
    };
    vector<edge> g[200005];
    int idx,dist[200005],dep[200005],dfn[200005],fa[200005][23],sz[200005],id[200005];
    inline void dfs(int x,int f){
    	dfn[x]=++idx;
    	id[idx]=x;
    	fa[x][0]=f;
    	sz[x]=1;
    	foreach(it,g[x]){
    		int y=it->v,z=it->w;
    		if(y==f)	continue;
    		dist[y]=dist[x]+z;
    		dep[y]=dep[x]+1;
    		dfs(y,x);
    		sz[x]+=sz[y];
    	}
    }
    inline int LCA(int x,int y){
    	if(dep[x]<dep[y])	swap(x,y);
    	for(int i=22;i>=0;i--){
    		if(dep[x]-(1<<i)>=dep[y])	x=fa[x][i];
    	}
    	if(x==y)	return x;
    	for(int i=22;i>=0;i--){
    		if(fa[x][i]!=fa[y][i])	x=fa[x][i],y=fa[y][i];
    	}
    	return fa[x][0];
    }
    struct SegTree{
    	struct node{
    		int l,r,lca;
    	} s[200005<<2];
    	inline void build(int k,int l,int r){
    		s[k].l=l;s[k].r=r;
    		if(l==r){
    			s[k].lca=l;
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(k<<1,l,mid);
    		build(k<<1|1,mid+1,r);
    		s[k].lca=LCA(s[k<<1].lca,s[k<<1|1].lca);
    	}
    	inline int query(int k,int l,int r){
    		if(l<=s[k].l&&s[k].r<=r){
    			return s[k].lca;
    		}
    		int mid=(s[k].l+s[k].r)>>1;
    		if(r<=mid)		return query(k<<1,l,r);
    		else if(l>mid)	return query(k<<1|1,l,r);
    		else			return LCA(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
    	}
    } segt;
    struct hjtree{
    	struct node{
    		int l,r,ch[2],cnt;
    	} s[200005<<5];
    	int ncnt=0,rt[200005];
    	inline void build(int &k,int l,int r){
    		k=++ncnt;s[k].l=l;s[k].r=r;s[k].cnt=0;
    		if(l==r)	return;
    		int mid=(l+r)>>1;
    		build(s[k].ch[0],l,mid);
    		build(s[k].ch[1],mid+1,r);
    	}
    	inline void modify(int &k,int pre,int x){
    		k=++ncnt;s[k]=s[pre];s[k].cnt++;
    		if(s[k].l==s[k].r)	return;
    		int mid=(s[k].l+s[k].r)>>1;
    		if(x<=mid)	modify(s[k].ch[0],s[pre].ch[0],x);
    		else		modify(s[k].ch[1],s[pre].ch[1],x);
    		s[k].cnt=s[s[k].ch[0]].cnt+s[s[k].ch[1]].cnt;
    	}
    	inline int query(int k,int l,int r){
    //		cout<<s[k].l<<" "<<s[k].r<<" "<<s[k].cnt<<endl;
    		if(l<=s[k].l&&s[k].r<=r)	return s[k].cnt;
    		int mid=(s[k].l+s[k].r)>>1;
    		if(r<=mid)		return query(s[k].ch[0],l,r);
    		else if(l>mid)	return query(s[k].ch[1],l,r);
    		else			return query(s[k].ch[0],l,mid)+query(s[k].ch[1],mid+1,r);
    	}
    } hjt;
    inline int getcnt(int p,int l,int r){
    //	cout<<hjt.rt[0]<<" "<<hjt.rt[l-1]<<endl;
    //	cout<<hjt.query(hjt.rt[l-1],dfn[p],dfn[p]+sz[p]-1)<<endl;
    	return hjt.query(hjt.rt[r],dfn[p],dfn[p]+sz[p]-1)-hjt.query(hjt.rt[l-1],dfn[p],dfn[p]+sz[p]-1);
    }
    signed main(){
    	fz(i,1,n-1){
    		int u=read(),v=read(),w=read();
    		g[u].push_back(edge(u,v,w));
    		g[v].push_back(edge(v,u,w));
    	}
    	dfs(1,0);
    //	fz(i,1,n)	cout<<dfn[i]<<endl;
    	fz(i,1,22)	fz(j,1,n)	fa[j][i]=fa[fa[j][i-1]][i-1];
    	segt.build(1,1,n);
    	hjt.build(hjt.rt[0],1,n);
    	fz(i,1,n)	hjt.modify(hjt.rt[i],hjt.rt[i-1],dfn[i]);
    	int ans=0;
    //	cout<<LCA(2,5)<<endl;
    	while(m--){
    		int p=read(),l=read(),r=read();
    		p^=ans;l^=ans;r^=ans;
    		int lc=segt.query(1,l,r);
    		int num=getcnt(p,l,r);
    //		cout<<"lc="<<lc<<"	num="<<num<<endl;
    		if(num==r-l+1)	ans=dist[lc]-dist[p];
    		else if(num>0)	ans=0;
    		else{
    			int cur=p;
    			for(int i=20;i>=0;i--){
    				if(fa[cur][i]&&getcnt(fa[cur][i],l,r)==0)
    					cur=fa[cur][i];
    			}
    			cur=fa[cur][0];
    //			cout<<"cur="<<cur<<endl;
    			if(dist[cur]<dist[lc])	ans=dist[p]+dist[lc]-(dist[cur]<<1);
    			else					ans=dist[p]-dist[cur];
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    学习日报
    学习日报
    学习日报
    学习日报
    《人月神话》读后感(第一二章)
    线程
    for each
    类的访问属性
    异常
    输入输出流
  • 原文地址:https://www.cnblogs.com/ET2006/p/12796459.html
Copyright © 2011-2022 走看看