• [HEOI2016/TJOI2016]树


    来一发大暴力

    树链剖分无疑了
    
     对于某个询问节点,二分答案所在的深度,若该深度到该节点上的区间和>0,说明其中有满足条件的点,增加深度继续二分,否则减小深度
    
    线段树上的操作:单点修改+区间查询(区间和)
    

    关于时间:

    时间复杂度(O(nlog^{2}n))
    虽然不是最优解法,但能过了,稍微卡一下,总时间大概900ms,最大点300ms,如果(O(nlogn))的玩家太注重卡常的话还是可以碾的,当然我的代码还有优化余地...(比如传参部分可以用空间换时间,卡常玩家可以尝试一下(还有fread之类的都可以尝试一下))

    关于最优解法:我有一个绝妙的思路,这里篇幅太小写不小,你可以看别人的题解

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define writeln(x)  write(x),puts("")
    using namespace std;
    inline int read(){
    	int ans=0,f=1;char chr=getchar();
    	while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();}
    	while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
    	return ans*f;
    }void write(int x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }const int M=100005;char opt[2];
    int head[M<<1],ver[M<<1],x,y,nxt[M<<1],tot,n,m,dep[M],fa[M],tp[M],sz[M],son[M],idx[M],s[M<<2],rk[M];
    inline void add(int x,int y){ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;}
    void dfs1(int x,int f){
    	sz[x]=1;dep[x]=dep[f]+1,fa[x]=f;
    	for(register int i=head[x];i;i=nxt[i]){
    		if(!dep[ver[i]]){
    			dfs1(ver[i],x),sz[x]+=sz[ver[i]];
    			if(sz[son[x]]<sz[ver[i]]) son[x]=ver[i];
    		}
    	}
    }int t;
    void dfs2(int x,int topf){
    	idx[x]=++t;tp[x]=topf;rk[t]=x;
    	if(!son[x]) return;
    	dfs2(son[x],topf);
    	for(int i=head[x];i;i=nxt[i])
    		if(!idx[ver[i]]) dfs2(ver[i],ver[i]);
    }
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define mid (l+r>>1)
    inline void Push_Up(int i){s[i]=s[ls]+s[rs];}
    void Update(int i,int l,int r,int pos,int x){
    	if(l==r){s[i]=x;return;}
    	if(pos<=mid) Update(ls,l,mid,pos,x);
    	else Update(rs,mid+1,r,pos,x);
    	Push_Up(i);
    }
    int Query(int i,int l,int r,int ql,int qr){
    	if(ql<=l&&r<=qr) return s[i];int ans=0;
    	if(ql<=mid) ans+=Query(ls,l,mid,ql,qr);
    	if(qr>mid)  ans+=Query(rs,mid+1,r,ql,qr);
    	return Push_Up(i),ans;
    }
    inline void Ask(int x){
    	if(Query(1,1,n,idx[x],idx[x])) {cout<<x<<endl;return;}
    	while(x){
    		int t=Query(1,1,n,idx[tp[x]],idx[x]);
    		if(t==0){x=fa[tp[x]];continue;}
    		else{
    			register int ll=idx[tp[x]],rr=idx[x],midd,ans;
    			while(ll<=rr){
    				midd=ll+rr>>1;
    				if(Query(1,1,n,midd,rr)) ans=midd,ll=midd+1;
    				else rr=midd-1;
    			}return (void)(writeln(rk[ans]));
    		}
    	}
    }
    int main(){
    	n=read(),m=read();
    	for(register int i=1;i<n;++i)x=read(),y=read(),add(x,y),add(y,x);
    	dfs1(1,0),dfs2(1,1);Update(1,1,n,1,1);
    	while(m--){
    		scanf("%s",opt+1);x=read();
    		if(opt[1]=='Q')	Ask(x);
    		else	Update(1,1,n,idx[x],1);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    nginx缓存实战
    单机编排之Docker Compose
    NGINX镜像的制作
    k8s的kube-proxy
    k8s应用环境
    k8s ansible部署部署文档
    部署docker镜像仓库及高可用
    openstack高可用集群20-openstack计算节点宕机迁移方案
    openstack 租户控制台修改虚拟机账户密码
    如何修改openstack虚拟机密码
  • 原文地址:https://www.cnblogs.com/zhenglw/p/10754318.html
Copyright © 2020-2023  润新知