zoukankan      html  css  js  c++  java
  • 2020 牛客 NOIP 赛前集训营-S(第三场)- C 牛半仙的妹子Tree

    ( ext{Solution})

    容易得出询问节点为 (v) 时,需要找出一个节点 (u) 符合 ( ext{dis}(u,v)le t_v-t_u)

    然后我就懵了,不知道该怎么处理。但其实很简单,我们的思路类似于树状数组,线段树之类优化的思路:平均查询与插入的时间复杂度。所以相当于将 (u) 的数据先插入,再用 (v) 来查询。

    按照这个思路改写一下:(dep[u]+dep[v]-2 imes dep[ ext{LCA}(u,v)]le t_v-t_u)

    (dep[u]+t_u-2 imes dep[ ext{LCA}(u,v)]le t_v-dep[v])

    仔细思考一下这个不太好处理的 ( ext{LCA}),我们发现 (u)( ext{LCA}) 只会是 (u) 到根的链上的点,(v) 同理。我们可以用树剖来做这道题。

    具体就是处理出 (dep[u]+t_u-2 imes dep[ ext{LCA}(u,v)]) 的最小值。存储每条链的 (maxd)(这个可以在线段树上计算),然后每插入一个 (u),就更新其到根的链上的每一段的 (val) 值(即 (dep[u]+t_u))。

    查询就查到根的链上每一段的最小的 (dep[u]+t_u-2 imes dep[ ext{LCA}(u,v)]) 值即可。

    ( ext{Code})

    #include <cstdio>
    
    #define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
    
    #include <vector>
    using namespace std;
    
    const int maxn=1e5+5,inf=0x3f3f3f3f;
    
    int maxd[maxn<<2],n,m,dfn[maxn],siz[maxn],f[maxn],dep[maxn],son[maxn],pos[maxn],Dfn,tp[maxn],ans[maxn<<2],val[maxn<<2];
    vector <int> e[maxn];
    bool tag[maxn<<2];
    
    void dfs1(int u,int fa) {
    	siz[u]=1,f[u]=fa,dep[u]=dep[fa]+1;
    	for(int i=0;i<e[u].size();++i) {
    		int v=e[u][i];
    		if(v==fa) continue;
    		dfs1(v,u);
    		siz[u]+=siz[v];
    		if(siz[son[u]]<siz[v]) son[u]=v;
    	}
    }
    
    void dfs2(int u) {
    	pos[dfn[u]=++Dfn]=u;
    	if(son[u]) tp[son[u]]=tp[u],dfs2(son[u]);
    	for(int i=0;i<e[u].size();++i) {
    		int v=e[u][i];
    		if(v==f[u]||v==son[u]) continue;
    		tp[v]=v,dfs2(v);
    	}
    }
    
    void clear(int x) {ans[x]=val[x]=inf; tag[x]=1;}
    
    void Delete(int x) {
    	if(tag[x]) clear(x<<1),clear(x<<1|1),tag[x]=0;
    	val[x<<1]=Min(val[x<<1],val[x]);
    	val[x<<1|1]=Min(val[x<<1|1],val[x]);
    	ans[x<<1]=Min(ans[x<<1],val[x<<1]-2*maxd[x<<1]);
    	ans[x<<1|1]=Min(ans[x<<1|1],val[x<<1|1]-2*maxd[x<<1|1]);
    }
    
    void pushUp(int u) {
    	if(!u) return;
    	ans[u]=Min(val[u]-2*maxd[u],Min(ans[u<<1],ans[u<<1|1]));
    }
    
    void modify(int o,int l,int r,int L,int R,int k) {
    	if(l>R||r<L) return;
    	if(l>=L&&r<=R) return (void) (ans[o]=Min(ans[o],(val[o]=Min(val[o],k))-2*maxd[o]));
    	int mid=l+r>>1;
    	Delete(o);
    	modify(o<<1,l,mid,L,R,k); modify(o<<1|1,mid+1,r,L,R,k);
    	pushUp(o);
    } 
    
    void build(int o,int l,int r) {
    	ans[o]=val[o]=inf;
    	if(l==r) return (void) (maxd[o]=dep[pos[l]]);
    	int mid=l+r>>1;
    	build(o<<1,l,mid); build(o<<1|1,mid+1,r);
    	maxd[o]=Max(maxd[o<<1],maxd[o<<1|1]);
    }
    
    int query(int o,int l,int r,int L,int R) {
    	if(l>R||r<L) return inf;
    	if(l>=L&&r<=R) return ans[o];
    	int mid=l+r>>1;
    	Delete(o);
    	return Min(query(o<<1,l,mid,L,R),query(o<<1|1,mid+1,r,L,R));
    }
    
    void change(int u,int w) {
    	for(;u;u=f[tp[u]]) modify(1,1,n,dfn[tp[u]],dfn[u],w);
    }
    
    int ask(int u) {
    	int ret=inf;
    	for(;u;u=f[tp[u]]) ret=Min(ret,query(1,1,n,dfn[tp[u]],dfn[u]));
    	return ret;
    }
    
    int main() {
    	int u,v;
    	n=read(9),m=read(9);
    	rep(i,1,n-1) {
    		u=read(9),v=read(9);
    		e[u].push_back(v),e[v].push_back(u);
    	}
    	dfs1(1,0),tp[1]=1,dfs2(1); build(1,1,n);
    	rep(i,1,m) {
    		u=read(9),v=read(9);
    		if(u==1) change(v,dep[v]+i);
    		else if(u==2) clear(1);
    		else puts(ask(v)<=i-dep[v]?"wrxcsd":"orzFsYo");
    	}
    	return 0;
    }
    
  • 相关阅读:
    299. Bulls and Cows
    Canvas实现文字散粒子化
    jQuery触发a标签点击事件-为什么不跳转
    Java 理论与实践: 正确使用 Volatile 变量
    图片全屏背景 代码实例
    Canvas 唯美雨落代码实现
    开发过程中资源限制的挑战
    死锁
    如何减少并发编程中的上下文切换
    Cookie工具类
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/13866469.html
Copyright © 2011-2022 走看看