zoukankan      html  css  js  c++  java
  • 【CF1009F】Dominant Indices(长链剖分优化DP)

    点此看题面

    大致题意:(d(x,y))表示(x)子树内到(x)距离为(y)的点的个数,对于每个(x),求满足(d(x,y))最大的最小的(y)

    暴力(DP)

    首先让我们来思考如何暴力(DP)

    这应该还是比较简单的吧。

    直接设(f_{x,i})表示(x)的子树内,到(x)的距离为(i)的点的个数

    则不难推出转移方程:

    [f_{x,0}=1,f_{x,i}=sum f_{son_x,i-1} ]

    但这样显然跑不过,要优化。

    长链剖分

    这是一道长链剖分优化(DP)的典型例题。

    (len_x)(x)到叶节点的最长距离,则不难发现转移方程第二维(i)显然不可能超过(len_x)

    考虑使用指针(虽然我很不喜欢指针,但貌似这里必须用(2333)),对于每条长链顶点给它开一个长度为(len_x)的内存供它存储。

    然后,对于每条长链的第(i)个元素(t_i),我们就用第(i)个位置作为(f_{t_i,0})

    这样的好处就在于,对于一条长链,我们是可以直接让父节点从子节点那里继承答案的!

    是不是非常神奇?

    而对于非长儿子,我们暴力合并两条链。

    由于每条链只会被合并一次,因此复杂度就达到了无比优秀的(O(n))

    是不是很神奇?

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000000
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    using namespace std;
    int n,ee,lnk[N+5];struct edge {int to,nxt;}e[N<<1];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
    		Tp I void writeln(Con Ty& x) {write(x),pc('
    ');}
    		I void clear() {fwrite(FO,1,C,stdout),C=0;}
    		#undef D
    }F;
    class LongChainDissection//长链剖分优化DP
    {
    	private:
    		#define Assign(x) (f[x]=p,p+=len[x])//分配内存
    		#define F5(x,v) ((f[x][ans[x]]<f[x][v]||(f[x][ans[x]]==f[x][v]&&ans[x]>v))&&(ans[x]=v))//更新答案
    		int son[N+5],len[N+5],ans[N+5],*p,*f[N+5],_f[N+5];
    		I void dfs(CI x,CI lst)//DFS预处理长儿子与len数组
    		{
    			for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&
    				(dfs(e[i].to,x),len[e[i].to]>len[son[x]]&&(son[x]=e[i].to));
    			len[x]=len[son[x]]+1;
    		}
    		I void DP(CI x,CI lst)//DP
    		{
    			RI i,j;son[x]&&(f[son[x]]=f[x]+1,DP(son[x],x),ans[x]=ans[son[x]]+1);//优先处理长儿子,并继承答案
    			for(i=lnk[x];i;i=e[i].nxt) if(e[i].to^lst&&e[i].to^son[x])//枚举非长儿子
    				for(Assign(e[i].to),DP(e[i].to,x),j=1;j<=len[e[i].to];++j)//暴力合并
    					f[x][j]+=f[e[i].to][j-1],F5(x,j);f[x][0]=1,F5(x,0);
    		}
    	public:
    		I LongChainDissection() {p=_f;}I void Init() {dfs(1,0);}//初始化
    		I void Solve() {Assign(1),DP(1,0);for(RI i=1;i<=n;++i) F.writeln(ans[i]);}//DP并输出答案
    }D; 
    int main()
    {
    	RI i,x,y;for(F.read(n),i=1;i^n;++i) F.read(x,y),add(x,y),add(y,x);//读入+建边
    	return D.Init(),D.Solve(),F.clear(),0;//求解
    }
    
  • 相关阅读:
    ASP.NET存储过程自定义分页详解
    ajax php POST 提交例子
    一个用存储过程的基本分页及其调用
    DataGrid 存储过程的分页
    无刷新无限级菜单联动
    asp.net URL多参数傳值以及特殊符号传值问题
    ASP.NET页面间参数的传递
    Android动画开发——Animation动画效果
    android surface
    Android控件属性——android:cacheColorHint=“#00000000”
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF1009F.html
Copyright © 2011-2022 走看看