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;
    }
    
  • 相关阅读:
    重新想象 Windows 8 Store Apps (15) 控件 UI: 字体继承, Style, ControlTemplate, SystemResource, VisualState, VisualStateManager
    重新想象 Windows 8 Store Apps (12) 控件之 GridView 特性: 拖动项, 项尺寸可变, 分组显示
    返璞归真 asp.net mvc (10) asp.net mvc 4.0 新特性之 Web API
    与众不同 windows phone (29) Communication(通信)之与 OData 服务通信
    与众不同 windows phone (33) Communication(通信)之源特定组播 SSM(Source Specific Multicast)
    与众不同 windows phone (27) Feature(特性)之搜索的可扩展性, 程序的生命周期和页面的生命周期, 页面导航, 系统状态栏
    与众不同 windows phone (30) Communication(通信)之基于 Socket TCP 开发一个多人聊天室
    返璞归真 asp.net mvc (12) asp.net mvc 4.0 新特性之移动特性
    重新想象 Windows 8 Store Apps (2) 控件之按钮控件: Button, HyperlinkButton, RepeatButton, ToggleButton, RadioButton, CheckBox, ToggleSwitch
    重新想象 Windows 8 Store Apps (10) 控件之 ScrollViewer 特性: Chaining, Rail, Inertia, Snap, Zoom
  • 原文地址:https://www.cnblogs.com/ET2006/p/12796459.html
Copyright © 2011-2022 走看看