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;
    }
    
  • 相关阅读:
    LeetCode 382. Linked List Random Node
    LeetCode 398. Random Pick Index
    LeetCode 1002. Find Common Characters
    LeetCode 498. Diagonal Traverse
    LeetCode 825. Friends Of Appropriate Ages
    LeetCode 824. Goat Latin
    LeetCode 896. Monotonic Array
    LeetCode 987. Vertical Order Traversal of a Binary Tree
    LeetCode 689. Maximum Sum of 3 Non-Overlapping Subarrays
    LeetCode 636. Exclusive Time of Functions
  • 原文地址:https://www.cnblogs.com/asuldb/p/10675041.html
Copyright © 2011-2022 走看看