zoukankan      html  css  js  c++  java
  • UOJ Round48:Goodbye Wuxu C. 新年的小黄鸭

    35 pts:

    (f[i][j])表示在(i)节点,当前重链顶端到当前点距离为(j)的最优方案。

    复杂度是(O(n^2))

    100 pts:

    自己的理解可能跟题解有点偏差。

    考虑dp的一个(f[i][j]) 一定会转移到0之后才对非(j-1)的位置造成贡献。

    我们转换一下,即每个位置所在的重链一定会通向叶子节点。

    考虑我们能不能直接通过数据结构找出那个叶子节点。考虑这一条链,我们将这一条链每个点的权值设置为这个点的父亲的其他儿子到达这条链时的(f),选这条链得到的答案就是这条链上的权值和再加上走这条链的贡献了。

    然后我们考虑这一条链上的值。我们在每个节点(2^i+1)级祖先打上这个点的标记,这样总共(nlog)个标记。

    (nlog) 个标记可以直接区间加到叶子节点上,这题就可以两个log做出来了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int anc[N][17],n;
    int hed[N],to[N<<1],nxt[N<<1],cnt,deg[N];
    inline void adde(int u,int v){
    	++cnt;to[cnt]=v,nxt[cnt]=hed[u];hed[u]=cnt;deg[u]++;
    }
    
    int t[N<<2],lzy[N<<2];
    inline void Add(int x,int l,int r,int ql,int qr,int sum){
    	if(ql<=l&&qr>=r){t[x]+=sum,lzy[x]+=sum;return ;}
    	int mid=(l+r)>>1;
    	if(ql<=mid)Add(x<<1,l,mid,ql,qr,sum);
    	if(qr>mid)Add(x<<1|1,mid+1,r,ql,qr,sum);
    	t[x]=min(t[x<<1],t[x<<1|1])+lzy[x];
    }
    inline int qry(int x,int l,int r,int ql,int qr){
    	if(ql<=l&&qr>=r)return t[x];
    	int mid=(l+r)>>1;
    	if(qr<=mid)return qry(x<<1,l,mid,ql,qr);
    	if(ql>mid)return qry(x<<1|1,mid+1,r,ql,qr);
    	return min(qry(x<<1,l,mid,ql,qr),qry(x<<1|1,mid+1,r,ql,qr))+lzy[x];
    }
    
    vector<int> Down[N];
    
    int in[N],out[N],dfn;
    int sz[N];
    
    inline void dfs(int x,int pre){
    	anc[x][0]=pre;
    	in[x]=dfn+1;sz[x]=1;
    	if(pre)Down[pre].push_back(x);
    	for(int i=1;i<17;i++)anc[x][i]=anc[anc[x][i-1]][i-1];
    	for(int i=0;i<17;i++)Down[anc[anc[x][i]][0]].push_back(x);
    	if(deg[x]==1&&pre)++dfn;
    	for(int i=hed[x];i;i=nxt[i])if(to[i]!=pre){
    		int v=to[i];dfs(v,x);sz[x]+=sz[v];
    	}
    	out[x]=dfn;
    }
    
    int f[N];
    
    inline void dfs2(int x,int pre){
    	int sum=0;
    	for(int i=hed[x];i;i=nxt[i]){int v=to[i];if(v==pre)continue;dfs2(v,x);}
    	for(int i=hed[x];i;i=nxt[i]){
    		int v=to[i];if(v==pre)continue;
    		sum+=f[v]+sz[v];
    	}
    	for(int i=hed[x];i;i=nxt[i]){
    		int v=to[i];if(v==pre)continue;
    		Add(1,1,dfn,in[v],out[v],sum-f[v]-sz[v]);
    	}
    	for(size_t i=0;i<Down[x].size();i++){int v=Down[x][i];
    		Add(1,1,dfn,in[v],out[v],sz[v]);
    	}
    	f[x]=qry(1,1,dfn,in[x],out[x]);
    	for(size_t i=0;i<Down[x].size();i++){int v=Down[x][i];
    		Add(1,1,dfn,in[v],out[v],-sz[v]);
    	}
    }
    
    int main()
    {
    	cin >> n;
    	for(int i=1;i<n;i++){
    		int u,v;scanf("%d%d",&u,&v);
    		adde(u,v),adde(v,u);
    	}
    	dfs(1,0);dfs2(1,0);cout << f[1] << endl;
    }
    
  • 相关阅读:
    关于RGB屏调试的一些知识(转)
    分享调试SI4432的一些小经验(转)
    音频压缩SPEEX应用,对讲机
    Codec 2 开源语音编解码器
    java导读
    视频监控知识汇总
    “inno setup打包,win7下安装没有桌面快捷方式,xp下安装正常”
    MFC设置窗体大小SetWindowPos
    C++中运行外部程序
    C++调用外部应用程序的方法的整理总结(常用)
  • 原文地址:https://www.cnblogs.com/weiyanpeng/p/11053816.html
Copyright © 2011-2022 走看看