• Codechef BTREE Union on Tree


    Link
    首先可以很自然地想到把虚树建出来然后在上面搞。
    我们做两遍dp,把每个点的(r_i)更新成从这个点出来能覆盖的最远距离和从其他点出来经过这个点后能够覆盖的最远距离的最大值。
    这样我们保证了对于一条边((u,v))(u)(v)的父亲),一定存在一个点(w)使得(v)(u)更新(w)更优。
    那么我们先计算出所有更新后(U(x_i,r_i))能够覆盖到的点的数目。
    这样子肯定会算重,我们再考虑把算重的减掉。
    算重的部分相当于找到上文说的那个(w),计算有多少点在(w)上面并且被(v)的范围包含,以及在(w)下面并且被(u)的范围包含。
    (r_u-(dep_w-dep_u)=r_v-(dep_v-dep_w))可以确定(w)的位置。
    同时可以发现(w)往上往下延伸的范围是相等的,这就相当于是(U(w,r_u-(dep_w-dep_u)))
    那么我们现在需要做的就是求(|U(x,r)|)
    这个可以建出点分树然后暴力跳父亲一层层统计。
    注意到(w)可能在边上,所以一开始化边为点即可。

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<numeric>
    #include<cstring>
    #include<algorithm>
    namespace IO
    {
        char ibuf[(1<<21)+1],*iS,*iT;
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
    }
    using IO::read;
    const int N=100007;
    int n,m;
    std::vector<int>e[N];
    namespace TreeI
    {
        int all,root,mx[N],size[N],vis[N],dep[N],dis[N][20],fa[N][20],cnt[N];
        std::vector<int>vec[N][2];
        void findroot(int u,int fa)
        {
    	size[u]=1,mx[u]=0;
    	for(int v:e[u]) if(!vis[v]&&v^fa) findroot(v,u),size[u]+=size[v],mx[u]=std::max(mx[u],size[v]);
    	mx[u]=std::max(mx[u],all-size[u]),root=mx[u]<mx[root]? u:root;
        }
        void calc(int u,int f,int root,int d)
        {
    	cnt[root]+=u<=n,vec[root][0][d]+=u<=n,vec[root][1][dis[u][dep[u]]]+=u<=n,fa[u][++dep[u]]=root,dis[u][dep[u]]=d;
    	for(int v:e[u]) if(!vis[v]&&v^f) calc(v,u,root,d+1);
        }
        void solve(int u)
        {
    	int tot=all;vis[u]=1,vec[u][0].resize(tot+2),vec[u][1].resize(tot+2),calc(u,0,u,0);
    	for(int i=0;i<2;++i) std::partial_sum(vec[u][i].begin(),vec[u][i].end(),vec[u][i].begin());
    	for(int v:e[u]) if(!vis[v]) all=size[v]>size[u]? tot-size[u]:size[v],findroot(v,root=0),solve(root);
        }
        int query(int u,int p,int o){return !u? 0:(p>(int)vec[u][o].size()-1? cnt[u]:vec[u][o][p]);}
        int query(int u,int r)
        {
    	int s=0;
    	if(r<0)return 0;
    	for(int i=dep[u];i;--i) if(r>=dis[u][i]) s+=query(fa[u][i],r-dis[u][i],0)-query(fa[u][i+1],r-dis[u][i],1);
    	return s;
        }
        void build(){mx[0]=all=2*n-1,findroot(1,root=0),solve(root);}
    }
    namespace TreeII
    {
        int fa[N],dep[N],size[N],son[N],top[N],dfn[N],id[N];
        void dfs1(int u,int f)
        {
    	fa[u]=f,dep[u]=dep[f]+1,size[u]=1;
    	for(int v:e[u]) if(v^f) dfs1(v,u),size[u]+=size[v],son[u]=size[son[u]]>size[v]? son[u]:v;
        }
        void dfs2(int u,int tp)
        {
    	top[u]=tp,id[dfn[u]=++dfn[0]]=u;
    	if(son[u]) dfs2(son[u],tp);
    	for(int v:e[u]) if(v^fa[u]&&v^son[u]) dfs2(v,v);
        }
        int lca(int u,int v){for(;top[u]^top[v];v=fa[top[v]])if(dep[top[u]]>dep[top[v]])std::swap(u,v);return dep[u]<dep[v]? u:v;}
        int jump(int u,int d){for(;dep[top[u]]>d;u=fa[top[u]]);return id[dfn[u]-dep[u]+d];}
        void build(){dfs1(1,0),dfs2(1,1);}
    }
    namespace TreeIII
    {
        using TreeII::dep;
        int top,cnt,a[N],vis[N],r[N],stk[N],fa[N];
        void dfs(int u)
        {
    	a[++cnt]=u;
    	if(!vis[u]) r[u]=-1;
    	for(int v:e[u]) fa[v]=u,dfs(v);
    	e[u].clear();
        }
        void work()
        {
    	m=read(),cnt=0;int ans=0;
    	for(int i=1;i<=m;++i) a[i]=read(),r[a[i]]=read()*2,vis[a[i]]=1;
    	std::sort(a+1,a+m+1,[](int u,int v){return TreeII::dfn[u]<TreeII::dfn[v];}),stk[top=1]=1;
    	for(int i=1,u,v;i<=m;++i)
    	{
                u=a[i],v=TreeII::lca(u,stk[top]);
                while(dep[v]<dep[stk[top]])
    	    {
                    if(dep[v]>=dep[stk[top-1]])
    		{
                        e[v].push_back(stk[top]),--top;
                        if(stk[top]^v) stk[++top]=v;
                        break;
                    }
    		e[stk[top-1]].push_back(stk[top]),--top;
                }
                if(stk[top]^u) stk[++top]=u;
            }
    	for(;top>1;--top) e[stk[top-1]].push_back(stk[top]);
    	dfs(1);
            for(int i=cnt;i^1;--i) r[fa[a[i]]]=std::max(r[fa[a[i]]],r[a[i]]-dep[a[i]]+dep[fa[a[i]]]);
    	for(int i=2;i<=cnt;++i) r[a[i]]=std::max(r[a[i]],r[fa[a[i]]]-dep[a[i]]+dep[fa[a[i]]]);
    	for(int i=1;i<=cnt;++i) ans+=TreeI::query(a[i],r[a[i]]);
    	for(int i=2,u,v,w;i<=cnt;++i) u=a[i],v=fa[u],w=TreeII::jump(u,(dep[u]-r[u]+dep[v]+r[v])/2),ans-=TreeI::query(w,r[u]-dep[u]+dep[w]);
    	printf("%d
    ",ans);
    	for(int i=1;i<=cnt;++i) vis[a[i]]=0;
    }
    }
    int main()
    {
        n=read();
        for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].push_back(i+n),e[v].push_back(i+n),e[i+n].push_back(u),e[i+n].push_back(v);
        TreeI::build(),TreeII::build();
        for(int i=1;i<2*n;++i) e[i].clear();
        for(int q=read();q;--q) TreeIII::work();
    }
    
  • 相关阅读:
    被忽视的调试工具Swagger
    MongoDB操作
    js获取当月第一天和最后一天
    vue中 关于$emit的用法
    map和flatmap的区别
    element 的el-dialog 浮层嵌套,第二次弹出的会被遮住
    el-table加背景色
    java 正则表达式匹配
    Python自动化测试 (七)logging 日志模块
    git安装配置与使用
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12310624.html
Copyright © 2020-2023  润新知