• Dsu On Tree-启发式树上合并


    简介

    1. 可以解决区间众数问题
    2. 不能支持修改,只能支持子树统计,不能链上统计。
    3. 和并查集无关

    理解

    假设给定一棵树,每个节点都有自己的颜色,现多次询问要求以某结点为根的子树内数量最多的颜色的编号。暴力即是对于询问
    的每一个节点递归统计颜色求最大,但是如果数据过大即使预处理各节点答案也可以导致n2复杂度。考虑每个节点的求解过程,都是要统计完子树的才更新自己,我们如果把统计子树内颜色个数的数组定为cnt,则cnt在一个子树用完后被另一个子树用时必须清空,这导致了低效。可以发现统计子树的颜色时,最后一个被统计的子树不必被清空,这在递归中自然不好特判,但我们可以利用这个性质,先求出非重子树的贡献,清空cnt,再求出重子树cnt,并利用这时的cnt再跑一遍非重子树加上其贡献。复杂度可以达到令人惊讶的O(nlogn);

    Lomsat gelral

    分析

    已经分析了吧...

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define lson x<<1
    #define rson x<<1|1
    #define ll long long
    #define rint register int
    #define mid  ((L + R) >> 1)
    using namespace std;
    template <typename xxx> inline void read(xxx &x) {
    	char c = getchar(),f = 1;x = 0;
    	for(;c ^ '-' && !isdigit(c);c = getchar());
    	if(c == '-') c = getchar(),f = -1;
    	for(;isdigit(c);c = getchar()) x = (x<<1) + (x<<3) + (c ^ '0');
    	x *= f;
    }
    template<typename xxx>void print(xxx x)
    {
        if(x<0){putchar('-');x=-x;}
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    const int maxn = 100010;
    const int inf = 0x7fffffff;
    const int mod = 1e9 + 7;
    struct edge{
    	int to,last;
    }e[maxn<<1];
    int head[maxn],tot;
    void add(int from,int to) {
    	++tot;
    	e[tot].to = to;
    	e[tot].last = head[from];
    	head[from] = tot;
    }
    int siz[maxn],son[maxn];
    void dfs(int x,int da) {//重链剖分 
    	siz[x] = 1;
    	for(rint i = head[x]; i; i = e[i].last) {
    		if(e[i].to == da) continue;
    		dfs(e[i].to,x);
    		siz[x] += siz[e[i].to];
    		if(son[x] == 0 || siz[son[x]] < siz[e[i].to]) son[x] = e[i].to;
    	}
    	return ;
    }
    int cnt[maxn];
    ll sum,ans[maxn],Mx,Tem,col[maxn];
    void deal(int x,int da,int val) {
    	cnt[col[x]] +=val;//因题而异 
    	if(cnt[col[x]] > Mx) Mx = cnt[col[x]],sum = col[x];
    	else if(cnt[col[x]] == Mx) sum += col[x];
    	for(rint i = head[x]; i; i = e[i].last) {
    		if(e[i].to == da || e[i].to == Tem) continue;
    		deal(e[i].to,x,val);
    	}
    }
    void ddfs(int x,int da,int opt) {
    	for(rint i = head[x]; i; i = e[i].last) {
    		if(e[i].to == da) continue;
    		if(e[i].to ^ son[x]) ddfs(e[i].to,x,0);//暴力统计轻边的贡献,opt = 0表示递归完成后要消除对该点的影响
    	}
    	if(son[x]) ddfs(son[x],x,1),Tem = son[x];//统计重儿子的贡献,不消除影响
    	deal(x,da,1);Tem = 0;//暴力统计所有轻儿子的贡献
    	ans[x] = sum;//更新答案 
    	if(!opt) deal(x,da,-1),sum = 0,Mx = 0;//如果需要删除贡献的话就删掉
    	return ; 
    }
    int n;
    int main()
    {
    	read(n);
    	for(rint i = 1;i <= n; ++i) read(col[i]);
    	for(rint i = 2;i <= n; ++i) {
    		int x,y;
    		read(x);read(y);
    		add(x,y);add(y,x);
    	}
    	dfs(1,0);
    	ddfs(1,0,0);
    	for(rint i = 1;i <= n; ++i) print(ans[i]),putchar(' ');
    	return 0;
    }
    /*
    
    */
    
    

    Blood Cousins

    分析

    和上一题差不多,转化一下就好了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define lson x<<1
    #define rson x<<1|1
    #define ll long long
    #define rint register int
    #define mid  ((L + R) >> 1)
    using namespace std;
    template <typename xxx> inline void read(xxx &x) {
    	char c = getchar(),f = 1;x = 0;
    	for(;c ^ '-' && !isdigit(c);c = getchar());
    	if(c == '-') c = getchar(),f = -1;
    	for(;isdigit(c);c = getchar()) x = (x<<1) + (x<<3) + (c ^ '0');
    	x *= f;
    }
    template<typename xxx>void print(xxx x)
    {
        if(x<0){putchar('-');x=-x;}
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    const int maxn = 200110;
    const int inf = 0x7fffffff;
    const int mod = 1e9 + 7;
    struct edge{
    	int to,last;
    }e[maxn<<1];
    int tot,head[maxn];
    inline void add(int from,int to) {
    	++tot;
    	e[tot].to = to;
    	e[tot].last = head[from];
    	head[from] = tot;
    }
    int n,m;
    struct node{int id,dth;};
    vector<node>q[maxn];
    int fa[22][maxn],lg[maxn];
    int son[maxn],siz[maxn];
    ll tem;
    int ans[maxn],cnt[maxn];
    int dep[maxn];
    inline void dfs(int x,int da) {
    	dep[x] = dep[da] + 1;
    	fa[0][x] = da;siz[x] = 1;
    	for(rint i = 1;i <= lg[dep[x]]; ++i) {
    		fa[i][x] = fa[i - 1][fa[i - 1][x]];
    	}
    	for(rint i = head[x];i;i = e[i].last) {
    		if(e[i].to == da) continue;
    		dfs(e[i].to,x); 
    		siz[x] += siz[e[i].to];
    		if(son[x] == 0 || siz[son[x]] < siz[e[i].to]) son[x] = e[i].to;
    	}
    	return;
    }
    inline void deal(int x,int da,int val) {
    	cnt[dep[x]] += val;
    	for(rint i = head[x];i;i = e[i].last) {
    		if(e[i].to == tem || e[i].to == da) continue;
    		deal(e[i].to,x,val);
    	}
    	return ;
    }
    inline void ddfs(int x,int da,int opt) {
    	for(rint i = head[x];i;i = e[i].last) {
    		if(e[i].to == da || e[i].to == son[x]) continue;
    		ddfs(e[i].to,x,0);
    	}
    	if(son[x]) ddfs(son[x],x,1),tem = son[x];
    	deal(x,da,1);
    	tem = 0;
    	int lim = q[x].size();
    	for(rint i = 0;i < lim ; ++i) ans[q[x][i].id] = cnt[q[x][i].dth] - 1;
    	if(!opt) deal(x,da,-1);
    	return;
    }
    inline int gt(int x,int y) {
    	while(y) 
    	x=fa[lg[y]][x],
    	y-=(1<<lg[y]);
        return x;
    }
    int main()
    {
    	read(n);
    	for(rint i = 2;i <= n; ++i) lg[i] = lg[i >> 1] + 1;
    	for(rint i = 1;i <= n; ++i) {
    		int x;read(x);
    		++x;//以1为超级节点 
    		add(x,i + 1);
    	}
    	dep[0] = -1;
    	dfs(1,0);
    	read(m);
    	for(rint i = 1;i <= m; ++i) {
    		int x,y;
    		read(x);read(y);++x; 
    //		cout<<gt(x,y)<<endl;
    		if(dep[x] < y + 1) continue;
    		q[gt(x,y)].push_back((node){i,dep[x]});
    	}
    	ddfs(1,0,0);
    	for(rint i = 1;i <= m; ++i) print(ans[i]),putchar(' '); 
    	return 0;
    }
    /*
    5 6 1
    0 4
    0 1 5
    1 2 5
    2 3 5
    3 4 5
    2 3 3
    0 2 100
    */
    
    

    推荐博客1博客2博客3

  • 相关阅读:
    Android获取视频音频的时长的方法
    Android动画效果之Frame Animation(逐帧动画)
    去除自定义Toolbar中左边距
    Android Toolbar样式定制详解
    Android 5.x Theme 与 ToolBar 实战
    Android ToolBar 使用完全解析
    Android开发:最详细的 Toolbar 开发实践总结
    SpannableString 转换局部字体大小,但在EditText测量之前设置内容,测量高度为,字体变小之前的高度
    android在Service中弹出Dialog对话框,即全局性对话框
    Could not find com.android.tools.build:gradle:3.0.0-alpha3
  • 原文地址:https://www.cnblogs.com/Thomastine/p/11815203.html
Copyright © 2020-2023  润新知