zoukankan      html  css  js  c++  java
  • 【CF1009F】Dominant Indices

    题目

    长链剖分板子题啊

    长链剖分有几个神奇的性质

    1. 所有长链的总点数为(n)

    2. 任意一个点的(k)级祖先所在长链的长度肯定不小于(k)

    3. 从任意点到根经过的短边数量不超过(sqrt{n}),也就是用长链剖分求(LCA)是根号复杂度的。。

    最后一个性质是这样的,从一个点往上经过一条短边,点数要加(1),再经过一条短边,点数要加(2),经过一共(k)条短边,点数要加(frac{k(k+1)}{2}),于是短边次数就是(sqrt{n})级别的

    之后长链剖分可以(O(1))(k)级祖先,不过好像没什么用啊,最主要的作用还是用来优化一些树上跟深度有关系的转移,可以做到均摊(O(n))复杂度

    比如说这道题我们设(f[x][j])表示在(x)的子树中距离(x)深度为(j)的点有多少个

    我们需要另(x)直接继承其长儿子的状态,就是(f[x][j+1]=f[son[x]][j]),这个需要用指针(O(1))实现

    之后对于所有的短儿子,我们直接暴力合并过去

    我们发现这样之后在一个点不是其父亲的长儿子的时候会暴力合并,代价是这条长链的长度,根据性质(1),所有长链的长度为(n),所以这个算法是均摊(O(n))

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=1000005;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct E{int v,nxt;}e[maxn<<1];
    int head[maxn],deep[maxn],len[maxn],son[maxn];
    int n,num,tax[maxn],*id=tax,*f[maxn],ans[maxn];
    inline void add(int x,int y) {
    	e[++num].v=y;e[num].nxt=head[x];head[x]=num;
    }
    void dfs1(int x) {
    	int maxx=-1;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(deep[e[i].v]) continue;
    		deep[e[i].v]=deep[x]+1;
    		dfs1(e[i].v);
    		if(len[e[i].v]>maxx) maxx=len[e[i].v],son[x]=e[i].v;
    	}
    	len[x]=len[son[x]]+1;
    }
    void dfs(int x) {
    	f[x][0]=1;
    	if(son[x]) f[son[x]]=f[x]+1,dfs(son[x]),ans[x]=ans[son[x]]+1;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(deep[e[i].v]<deep[x]||e[i].v==son[x]) continue;
    		f[e[i].v]=id;id+=len[e[i].v];dfs(e[i].v);
    		for(re int j=1;j<=len[e[i].v];j++) {
    			f[x][j]+=f[e[i].v][j-1];
    			if(f[x][j]>f[x][ans[x]]||(f[x][j]==f[x][ans[x]]&&j<ans[x]))
    				ans[x]=j;
    		}
    	}
    	if(f[x][ans[x]]==1) ans[x]=0;
    }
    int main() {
    	n=read();
    	for(re int x,y,i=1;i<n;i++)
    		x=read(),y=read(),add(x,y),add(y,x);
    	deep[1]=1,dfs1(1);
    	f[1]=id,id+=len[1];dfs(1);
    	for(re int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    hexo 建站参考
    如何在element-UI 组件的change事件中传递自定义参数
    vue 项目中当访问路由不存在的时候默认访问404页面
    百度地图引用时 报出A Parser-blocking, cross site (i.e. different eTLD+1) script
    echarts之legend-改变图例的图标为自定义图片
    大数据浪潮下的前端工程师
    为什么要使用TypeScript开发Web应用程序
    【转】简单理解Vue中的nextTick
    vue项目如何刷新当前页面
    安装Genymotion android模拟器
  • 原文地址:https://www.cnblogs.com/asuldb/p/10675041.html
Copyright © 2011-2022 走看看