2021牛客暑期多校训练营7 F-xay loves trees(线段树+滑动窗口)

F-xay loves trees

考虑在树1中满足条件的一些点,首先不难想到一定是一条链,其次如果点 u u u被选择那么在树2以 u u u为根的子树的点就禁止被选,于是只需区间+,然后查询区间最值是否存在>1也就是树2中覆盖次数超过2的节点即可。

首先不难想到可以二分链的长度,在树1中进行dfs用双端队列维护维护长度是len的链 2log跑不过。

假如我们dfs到某个点我们假如我们发现长度为len是可以那么我们就可以保存这个长度去维护滑动窗口类似!因为答案肯定不会比len还短,维护短的没意义,那么这个长度就是单调递增的,那么这样就没二分了!
黑夜和白天大佬题解

Code1 二分
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int rd()
{
    int res=0;
    char ch=getchar();
    while(!isdigit(ch)) {ch=getchar();}
    while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res;
}
const int N=300010;
int h1[N],e[N<<2],ne[N<<2],idx;
int h2[N];
void add(int h[],int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
int sz[N],dfn[N];
int n,timestamp;
void dfs1(int u,int fa)
{
    sz[u]=1;
    dfn[u]=++timestamp;
    for(int i=h1[u];i!=-1;i=ne[i])
    {
        int v=e[i];
        if(v==fa) continue;
        dfs1(v,u);
        sz[u]+=sz[v];
    }
}
int len;
bool ok;
int q[N],tt;
int val[N<<2],tag[N<<2];
void pushdown(int u)
{
    if(tag[u]==0) return;
    tag[u<<1]+=tag[u];
    tag[u<<1|1]+=tag[u];
    val[u<<1]+=tag[u];
    val[u<<1|1]+=tag[u];
    tag[u]=0;
}
int dep[N],f2[N];
void dfs3(int u)
{
    for(int i=h2[u];i!=-1;i=ne[i])
    {
        int v=e[i];
        if(v==f2[u]) continue;
        dep[v]=dep[u]+1;
        f2[v]=u;
        dfs3(v);
    }
}
void modify(int u,int l,int r,int L,int R,int v)
{
    if(L<=l&&r<=R) 
    {
        val[u]+=v;
        tag[u]+=v;
        return;
    }
    pushdown(u);
    int mid=l+r>>1;
    if(L<=mid) modify(u<<1,l,mid,L,R,v);
    if(R>mid) modify(u<<1|1,mid+1,r,L,R,v);
    val[u]=max(val[u<<1],val[u<<1|1]);
}
void dfs2(int u)
{
    if(ok) return;
    int cur=dep[u];
    if(cur>=len)  
    {
        int v=q[tt-len+1];
        modify(1,1,n,dfn[v],dfn[v]+sz[v]-1,-1);
    }
    q[++tt]=u;
    modify(1,1,n,dfn[u],dfn[u]+sz[u]-1,1);
    if(cur+1>=len)
    {
        ll tot=val[1];
        if(tot<=1) ok=1;
    }
    for(int i=h2[u];i!=-1;i=ne[i])
    {
        int v=e[i];
        if(v==f2[u]) continue;
        dfs2(v);
    }
    --tt;
    modify(1,1,n,dfn[u],dfn[u]+sz[u]-1,-1);
    if(cur>=len)  
    {
        int v=q[tt-len+1];
        modify(1,1,n,dfn[v],dfn[v]+sz[v]-1,1);
    }
}
bool check(int x)
{
    len=x;
    ok=0;
    tt=0;
    dfs2(1);
    return ok;
}
void init()
{
    for(int i=1;i<=n;i++) h1[i]=h2[i]=-1;
    idx=timestamp=0;
    tt=0;
    for(int i=1;i<=n;i++) dfn[i]=sz[i]=0;
    for(int i=1;i<=n;i++) dep[i]=f2[i]=0;
}
int main()
{
    int Tc=rd();
    while(Tc--)
    {
        n=rd();
        init();
        for(int i=1;i<n;i++)
        {
            int u=rd(),v=rd();
            add(h2,u,v);
            add(h2,v,u);
        }
        for(int i=1;i<n;i++)
        {
            int u=rd(),v=rd();
            add(h1,u,v);
            add(h1,v,u);
        }
        dfs1(1,0);
        dfs3(1);
        int l=1,r=1+*max_element(dep+1,dep+1+n);
        while(l<r)
        {
            int mid=l+r+1>>1;
            if(check(mid)) l=mid;
            else r=mid-1;
        }
        printf("%d\n",l);
    }
    return 0;
}
Code2 优化
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int rd()
{
    int res=0;
    char ch=getchar();
    while(!isdigit(ch)) {ch=getchar();}
    while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res;
}
const int N=300010;
int h1[N],e[N<<2],ne[N<<2],idx;
int h2[N];
void add(int h[],int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
int sz[N],dfn[N];
int n,timestamp;
void dfs2(int u,int fa)
{
    sz[u]=1;
    dfn[u]=++timestamp;
    for(int i=h2[u];i!=-1;i=ne[i])
    {
        int v=e[i];
        if(v==fa) continue;
        dfs2(v,u);
        sz[u]+=sz[v];
    }
}
int val[N<<2],tag[N<<2];
void pushdown(int u)
{
    if(tag[u]==0) return;
    tag[u<<1]+=tag[u];
    tag[u<<1|1]+=tag[u];
    val[u<<1]+=tag[u];
    val[u<<1|1]+=tag[u];
    tag[u]=0;
}
void modify(int u,int l,int r,int L,int R,int v)
{
    if(L<=l&&r<=R) 
    {
        val[u]+=v;
        tag[u]+=v;
        return;
    }
    pushdown(u);
    int mid=l+r>>1;
    if(L<=mid) modify(u<<1,l,mid,L,R,v);
    if(R>mid) modify(u<<1|1,mid+1,r,L,R,v);
    val[u]=max(val[u<<1],val[u<<1|1]);
}
void update(int u,int v){modify(1,1,n,dfn[u],dfn[u]+sz[u]-1,v);}
int ans;
int q[N],tt,hh;
void dfs1(int u,int fa)
{
    int cur=-1;
    q[++tt]=u;
    update(u,1);
    if(val[1]==1) ans=max(ans,tt-hh+1);
    else if(tt-hh+1>ans)
    {
        cur=q[hh++];
        update(cur,-1);
    }
    
    for(int i=h1[u];i!=-1;i=ne[i]) if(e[i]!=fa) dfs1(e[i],u);
    
    if(cur!=-1) 
    {
        update(cur,1);
        q[--hh]=cur;
    }
    update(u,-1);
    --tt;
}
void init()
{
    for(int i=1;i<=n;i++) h1[i]=h2[i]=-1;
    for(int i=1;i<=n;i++) dfn[i]=sz[i]=0;
    for(int i=1;i<=4*n;i++) tag[i]=val[i]=0;
    idx=timestamp=hh=ans=0;
    tt=-1;
}
int main()
{
    int Tc=rd();
    while(Tc--)
    {
        n=rd();
        init();
        for(int i=1;i<n;i++)
        {
            int u=rd(),v=rd();
            add(h1,u,v);
            add(h1,v,u);
        }
        for(int i=1;i<n;i++)
        {
            int u=rd(),v=rd();
            add(h2,u,v);
            add(h2,v,u);
        }
        dfs2(1,0);
        dfs1(1,0);
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值