• 2021牛客暑期多校训练营7


    F xay loves trees

    还是第一次做到这种两棵树(两个图)的题目,自然是不可能在两棵树上同时搞得,因为两棵树结构都不同....

    题目要求选的点在第一棵树上必须是连续的链状,在第二棵树上任何两个点都不能是祖宗,祖先的关系,换句话说在第二棵树上,任何一个点都不能是另一个点的子树中的点。

    既然第一棵树上的要求比较严苛,我们可以考虑在第一棵树上进行操作,将第二棵树上的要求当做第一棵树上的限制条件。

    因为在第一棵树上必须是链,这很符合我们的dfs的要求,我们将树上的链转化成序列上的问题思考怎么解决,对于这种区间最长的问题,我们很容易想到尺取法,我们可以找一下每个右端点最小的左端点,发现当右指针递增时,左指针也一定递增。譬如当右指针为r时,左指针为l,则当右指针为r+1时,左指针左边的一定不用再考虑了,因为r已经在区间内了,而r和l左边的有冲突,所以左指针也一定递增。这就保证了我们的复杂度是O(n)的。我们把它放到树上,也就是说在dfs的时候维护一个左右指针就行,那怎么判断当前的序列合不合法?由于在第二棵树上,任何一个点都不能是另一个点的子树中的点,所以我们可以每次选择一个节点后都将这个节点及其字数都染色,之后判断一个点是否可进入我们的序列中时,我们只需要判断它的子树中是否有值即可。若有值则之前选的点中一定有它的祖先或儿子。这用dfs序加线段树就行。

    //不等,不问,不犹豫,不回头.
    #include<bits/stdc++.h>
    #define _ 0
    #define ls p<<1
    #define db double
    #define rs p<<1|1
    #define P 1000000007
    #define ll long long
    #define INF 1000000000
    #define get(x) x=read()
    #define PLI pair<ll,int>
    #define PII pair<int,int>
    #define ull unsigned long long
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(x,y,z) for(int x=y;x<=z;++x)
    #define fep(x,y,z) for(int x=y;x>=z;--x)
    #define go(x) for(RE int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
    using namespace std;
    const int N=3e5+10;
    int dfn[N],Size[N],num,b[N],ans,n;
    vector<int>v1[N],v2[N];
    struct Tree
    {
        int l,r,tag,dat;
        #define l(x) t[x].l
        #define r(x) t[x].r
        #define tag(x) t[x].tag
        #define dat(x) t[x].dat
    }t[N<<2];
    
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    
    inline void init()
    {
        get(n);
        rep(i,1,n) v1[i].clear(),v2[i].clear();
        rep(i,1,n-1)
        {
            int get(x),get(y);
            v1[x].push_back(y);
            v1[y].push_back(x);
        } 
        rep(i,1,n-1)
        {
            int get(x),get(y);
            v2[x].push_back(y);
            v2[y].push_back(x);
        }
    }
    
    inline void dfs(int x,int father)
    {
        dfn[x]=++num;Size[x]=1;
        for(auto y:v2[x])
        {
            if(y==father) continue;
            dfs(y,x);
            Size[x]+=Size[y];
        }
    }
    inline void build(int p,int l,int r)
    {
        l(p)=l;r(p)=r;
        if(l==r) {dat(p)=tag(p)=0;return;}
        int mid=l+r>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        dat(p)=tag(p)=0;
    }
    
    inline void push(int p)
    {
        if(tag(p))
        {
            dat(ls)+=tag(p);
            dat(rs)+=tag(p);
            tag(ls)+=tag(p);
            tag(rs)+=tag(p);
            tag(p)=0; 
        }
    }
    
    inline int ask(int p,int l,int r)
    {
        if(l<=l(p)&&r>=r(p)) return dat(p);
        push(p);
        int mid=l(p)+r(p)>>1;
        int ans=-INF;
        if(l<=mid) ans=max(ans,ask(ls,l,r));
        if(r>mid) ans=max(ans,ask(rs,l,r));
        return ans;
    }
    
    inline void alter(int p,int l,int r,int k)
    {
        if(l<=l(p)&&r>=r(p))
        {
            dat(p)+=k;
            tag(p)+=k;
            return;
        }
        push(p);
        int mid=l(p)+r(p)>>1;
        if(l<=mid) alter(ls,l,r,k);
        if(r>mid) alter(rs,l,r,k);
        dat(p)=max(dat(ls),dat(rs));
    }
    
    inline void dfs(int x,int father,int l,int r)
    {
        ans=max(ans,r-l+1);
        for(auto y:v1[x])
        {
            if(y==father) continue;
            int L=l,R=r;//记录加入y之后的指针. 
            while(ask(1,dfn[y],dfn[y]+Size[y]-1))
            {
                alter(1,dfn[b[L]],dfn[b[L]]+Size[b[L]]-1,-1);
                L++;
            }
            alter(1,dfn[y],dfn[y]+Size[y]-1,1);
            b[++R]=y;
            dfs(y,x,L,R);
            rep(i,l,L-1) alter(1,dfn[b[i]],dfn[b[i]]+Size[b[i]]-1,1);
            alter(1,dfn[y],dfn[y]+Size[y]-1,-1);
        }
    } 
    
    int main()
    {
        //freopen("1.in","r",stdin);
        int get(T);
        while(T--)
        {
            init();
            num=0;dfs(1,0);
            build(1,1,n);
            ans=0;b[1]=1;
            alter(1,dfn[1],dfn[1]+Size[1]-1,1);
            dfs(1,0,1,1);
            put(ans);
        }
        return (0^_^0);
    }
    //以吾之血,铸吾最后的亡魂.
    View Code
  • 相关阅读:
    SQL语法结构
    MVC ViewBag不能使用在工程文件中添加引用
    Structs2+spring+hibernate整合
    java解析多层嵌套json字符串
    [转载] javamail腾讯企业邮箱发送邮件
    【转载】java加载properties文件的六种方法总结
    Linux上执行java文件——用Eclipse将Java源代码生成可执行文件
    ssm框架实现用户登录的拦截器和过滤器
    Sql Server设置用户只能查看并访问特定数据库
    Java操作Excel之POI:excel导出文件
  • 原文地址:https://www.cnblogs.com/gcfer/p/15117802.html
Copyright © 2020-2023  润新知