zoukankan      html  css  js  c++  java
  • Luogu P6071 [MdOI2020] Treequery

    好题。

    算法:dfs序,主席树(可持久化线段树),LCA。

    题目

    代码+解析

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #define g getchar()
    using namespace std;
    typedef long long ll;
    const int N=2e5+10;
    template<class o>void qr(o&x) {
    	char c=g;int f=1;x=0;
    	while(!isdigit(c)){if(c=='-')f=-1;c=g;}
    	while(isdigit(c))x=x*10+c-'0',c=g;
    	x*=f;
    }
    template<class o>void write(o x) {
    	if(x/10)write(x/10);
    	putchar(x%10+'0');
    }
    template<class o>void pri(o x) {
    	if(x<0)x=-x,putchar('-');
    	write(x);puts("");
    }
    
    int n,m,fa[N][20],dis[N],dep[N],in[N],ou[N],q[N],tot,ans;
    
    struct edge{int y,next,d;}a[N<<1]; int len,last[N];
    void ins(int x,int y,int d) {a[++len]=(edge){y,last[x],d};last[x]=len;}
    
    void dfs(int x) {
    	in[x]=++tot; q[tot]=x;
    	for(int k=last[x];k;k=a[k].next) {
    		int y=a[k].y; if(y==fa[x][0]) continue;
    		fa[y][0]=x; for(int i=1;fa[y][i-1];i++) fa[y][i]=fa[fa[y][i-1]][i-1];
    		dis[y]=dis[x]+a[k].d; dep[y]=dep[x]+1; dfs(y);
    	}
    	ou[x]=tot;
    }
    
    int lc[N*20],rc[N*20],c[N*20],cnt,root[N];
    
    void update(int &x,int y,int l,int r,int pos) {
    	lc[x=++cnt]=lc[y]; rc[x]=rc[y]; c[x]=c[y]+1; 
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	if(pos<=mid) update(lc[x],lc[y],l,mid,pos);
    	else 		 update(rc[x],rc[y],mid+1,r,pos);
    }
    
    int Qmin(int x,int y,int l,int r,int L,int R) {//在原始询问[l,r]中找到dfs序[L,R]内最小的数
    	 if(c[x]==c[y]||L>R) return -1;
    	 if(l==r) return q[l];
    	 int mid=(l+r)>>1,t=-1;
    	 if(L<=mid) t=Qmin(lc[x],lc[y],l,mid,L,R);
    	 if(mid<R&&t==-1) t=Qmin(rc[x],rc[y],mid+1,r,L,R);
    	 return t;
    } 
    
    int Qmax(int x,int y,int l,int r,int L,int R) {
    	if(c[x]==c[y]||L>R) return -1;
    	if(l==r) return q[l];
    	int mid=(l+r)>>1,t=-1;
    	if(mid<R) t=Qmax(rc[x],rc[y],mid+1,r,L,R);
    	if(L<=mid&&t==-1) t=Qmax(lc[x],lc[y],l,mid,L,R);
    	return t;
    }
    
    bool check(int x,int y) {//x是否在y子树内
    	return in[y]<=in[x]&&in[x]<=ou[y];
    }
    
    int LCA(int x,int y) {
    	if(dep[x]>dep[y]) swap(x,y);
    	for(int k=dep[y]-dep[x],i=0;k;i++)
    		if(k>>i&1) y=fa[y][i],k^=1<<i;
    	if(x==y) return x;
    	for(int i=17;i>=0;i--)
    		if(fa[x][i]^fa[y][i]) x=fa[x][i],y=fa[y][i];
    	return fa[x][0];
    }
    
    int solve(int p,int l,int r) {
    	int x,y;
    	int a=check(x=Qmin(root[r],root[l-1],1,n,1,n),p),
    		b=check(y=Qmax(root[r],root[l-1],1,n,1,n),p);
    	if(a^b)return 0;
    	if(a) return dis[LCA(x,y)]-dis[p];
    	a=Qmin(root[r],root[l-1],1,n,in[p],n),
    	b=Qmax(root[r],root[l-1],1,n,1,in[p]-1);
    	if(a==-1) a=x;
    	if(b==-1) b=y;
    	x=LCA(a,p); y=LCA(b,p);
    	if(x==y) return dis[LCA(a,b)]+dis[p]-2*dis[x];
    	else return dep[x]>dep[y]?dis[p]-dis[x]:dis[p]-dis[y];
    	/*
    	总共有三种情况:
    	1.有在p子树内的,又不在的,输出0.
    	2.全在p子树内的,输出LCA(l...r)->p.根据dfs序的性质可知:答案即为LCA(dfsmin,dfsmax)->p.
    	3.全在外。要么LCA(l...r,p)都相等,要么不等。分情况讨论即可。
    	
    	为了方便求出[l,r]的dfs序哪个位置最大,哪个最小。
    	我们把叶子节点定为dfs序。用可持久化线段树维护即可。 
    	*/
    }
    
    int main() {
    	qr(n); qr(m);
    	for(int i=1,x,y,d;i<n;i++)
    		qr(x),qr(y),qr(d),ins(x,y,d),ins(y,x,d);
    	dfs(1);
    	for(int i=1;i<=n;i++) update(root[i],root[i-1],1,n,in[i]);
    	while(m--) {
    		int p,l,r; qr(p); qr(l); qr(r);
    		p^=ans; l^=ans; r^=ans;
    		pri(ans=solve(p,l,r));
    	}
    	return 0;
    }
    
  • 相关阅读:
    最近总结
    公开MQTT服务器列表
    MQTT资料收集
    开源游戏
    B站学习资料
    MQTT资料
    都2020年了,还再问GET和POST的区别?【深度好文】
    以“用户登录”测试谈用例编写
    接口自动化测试框架9项必备功能
    一篇文章了解软件测试基础知识
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373868.html
Copyright © 2011-2022 走看看