• SP2939 QTREE5


    SP2939 QTREE5 - Query on a tree V解题报告:

    更好的阅读体验

    题意

    给定一棵 (n) 各点原始全白的树,(m) 次操作,支持单点颜色翻转以及查询一个点距离最近的黑点的距离。

    (1leqslant n,mleqslant 10^5)

    分析

    模拟赛题,好像有个简单的点分树写法,不过操作分块也可以轻松解决。(类似 CF342E

    对于修改操作,你直接维护单点的颜色;查询分为两部分:本块之前修改的点(本快操作中一定不存在修改),本块修改过的点、

    第一部分可以直接在每个块结束后维护出每个点距离这样的点的最短距离(bfs),第二部分则可以枚举点求距离直接判断。

    用了 (O(nlog n)-O(1)) 的 lca,时间复杂度 (O((n+m)sqrt m))

    代码

    #include<stdio.h>
    #include<math.h>
    #include<vector>
    #define inf 1000000000
    using namespace std;
    const int maxn=100005,maxm=200005,maxk=20,maxq=100005;
    int n,m,e,S,T,now,qs;
    int start[maxn],to[maxm],then[maxm],lg[maxn<<1],ST[maxn<<1][maxk],dep[maxn],in[maxn],bl[maxn],br[maxn],opt[maxq],k[maxq],dis[maxn],q[maxn],col[maxn],ok[maxn];
    inline int calc(int a,int b){
    	return dep[a]<dep[b]? a:b;
    }
    inline void add(int x,int y){
    	then[++e]=start[x],start[x]=e,to[e]=y;
    }
    void dfs(int x,int last){
    	dep[x]=dep[last]+1,in[x]=++qs,ST[qs][0]=x;
    	for(int i=start[x];i;i=then[i]){
    		int y=to[i];
    		if(y==last)
    			continue;
    		dfs(y,x);
    		ST[++qs][0]=x;
    	}
    }
    void getST(){
    	lg[0]=-1;
    	for(int i=1;i<=qs;i++)
    		lg[i]=lg[i/2]+1;
    	for(int i=1;i<=18;i++)
    		for(int j=1;j+(1<<i)-1<=qs;j++)
    			ST[j][i]=calc(ST[j][i-1],ST[j+(1<<(i-1))][i-1]);
    }
    int lca(int a,int b){
    	if(in[a]>in[b])
    		swap(a,b);
    	int l=in[a],r=in[b],k=lg[r-l+1];
    	return calc(ST[l][k],ST[r-(1<<k)+1][k]);
    }
    int getdis(int a,int b){
    	return dep[a]+dep[b]-2*dep[lca(a,b)];
    }
    void bfs(int a,int b,int c,int d){
    	int hd=1,tl=0;
    	if(c)
    		for(int i=c;i<=d;i++)
    			if(opt[i]==1)
    				ok[k[i]]=1;
    	for(int i=1;i<=n;i++){
    		if(col[i]==1&&ok[i]==0)
    			q[++tl]=i,dis[i]=0;
    		else dis[i]=inf;
    		ok[i]=0;
    	}
    	while(hd<=tl){
    		int x=q[hd++];
    		for(int i=start[x];i;i=then[i])
    			if(dis[to[i]]>dis[x]+1)
    				dis[to[i]]=dis[x]+1,q[++tl]=to[i];
    	}
    }
    int query(int x,int a,int b,int c){
    	int res=dis[x];
    	if(col[x])
    		res=0;
    	for(int i=a;i<=c;i++)
    		if(opt[i]==1&&col[k[i]]==1)
    			res=min(res,getdis(x,k[i]));
    	return res==inf? -1:res;
    }
    void read(int &x){
    	char c=getchar();
    	x=0;
    	for(;c<'0'||c>'9';c=getchar());
    	for(;c>='0'&&c<='9';c=getchar())
    		x=x*10+c-48;
    }
    int main(){
    	read(n);
    	for(int i=1,x,y;i<n;i++)
    		read(x),read(y),add(x,y),add(y,x);
    	read(m);
    	dfs(1,0),getST(),S=800,T=m/S;
    	for(int i=1;i<=T;i++)
    		bl[i]=br[i-1]+1,br[i]=i*S;
    	if(br[T]<m)
    		T++,bl[T]=bl[T-1]+1,br[T]=m;
    	for(int i=1;i<=n;i++)
    		dis[i]=inf;
    	for(int i=1;i<=m;i++)
    		read(opt[i]),read(k[i]),opt[i]++;
    	for(int i=1,lst=1;i<=m;i++){
    		if(i>br[lst])
    			bfs(bl[lst],br[lst],bl[lst+1],br[lst+1]),lst++;
    		if(opt[i]==1)
    			col[k[i]]^=1;
    		if(opt[i]==2)
    			printf("%d
    ",query(k[i],bl[lst],i,br[lst]));
    	}
    	return 0;
    }
    
  • 相关阅读:
    我的2018:OCR、实习和秋招
    【OCR技术系列之六】文本检测CTPN的代码实现
    【OCR技术系列之五】自然场景文本检测技术综述(CTPN, SegLink, EAST)
    如何免费使用谷歌搜索
    CUDA编程之快速入门
    我在北京实习的四个月
    在C++98基础上学习C++11新特性
    Linux编程之线程池的设计与实现(C++98)
    ASP.NET Core中使用IOC三部曲(三.采用替换后的Autofac来实现AOP拦截)
    ASP.NET Core文件上传与下载(多种上传方式)
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/15370893.html
Copyright © 2020-2023  润新知