• 数据结构 Week 3 --- dsu on tree 和 点分治


    做了几道dsu on tree后再写点分治,发现点分治的题都能用dsu on tree做

    然后发现这两者是有很多共同之处的

    • 都枚举了每个点为根节点
    • 都是nlogn的遍历
    • 大都记录了每个点到根节点的整条链的信息

    难度基本不大

    个人觉的还是dsu on tree好用一点,感觉代码量更小

    点分治的一题:

    P4178 Tree

    计算,计入(ad),清空(clear),套个树状数组

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    const int MAXN = 1e5+7;
    struct EDGE{
    	int to,w,next;
    }edge[MAXN*2];
    int head[MAXN],tot = 0;
    int n,m,u,v,w,k;
    int ans = 0;
    void add(int u,int v,int w){
    	tot++;
    	edge[tot].to = v;
    	edge[tot].w = w;
    	edge[tot].next = head[u];
    	head[u] = tot;
    }
    
    int rt,all;
    int siz[MAXN],maxp[MAXN];
    bool vis[MAXN];
    void getrt(int s,int f){
    	siz[s] = 1;
    	maxp[s] = 0;
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(po == f || vis[po]) continue;
    		getrt(po,s);
    		siz[s] += siz[po];
    		maxp[s] = max(maxp[s],siz[po]);
    	}	
    	maxp[s] = max(maxp[s],all - siz[s]);
    	if(maxp[s] < maxp[rt]) rt = s;
    }
    int bit[MAXN];
    int lowbit(int x) {return x & -x;}
    void ADD(int pos,int add){
    	for(int i = pos;i<=k;i+=lowbit(i)) bit[i] += add;
    }
    int Q(int pos){
    	int res = 0;
    	for(int i = pos;i;i-=lowbit(i)) res += bit[i];
    	return res; 
    }
    void calc(int s,int f,int lc){//计算 
    	ans++;//加上根节点到这个点本身 
    	ans += Q(k - lc);
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(po == f || vis[po]) continue;
    		int w = edge[i].w;
    		if(lc + w > k) continue;
    		calc(po,s,lc + w);
    	}	
    } 
    void ad(int s,int f,int lc){
    	ADD(lc,1);
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(po == f || vis[po]) continue;
    		int w = edge[i].w;
    		if(lc + w > k) continue;
    		ad(po,s,lc + w);
    	}
    }
    void clear(int s,int f,int lc){
    	ADD(lc,-1);
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(po == f || vis[po]) continue;
    		int w = edge[i].w;
    		if(lc + w > k) continue;
    		clear(po,s,lc + w);
    	}
    }
    void solve(int s){
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(vis[po]) continue;
    		int w = edge[i].w;
    		if(w > k)continue;
    		calc(po,s,w);
    		ad(po,s,w);
    	}
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(vis[po]) continue;
    		int w = edge[i].w;
    		if(w > k)continue;
    		clear(po,s,w);
    	}
    }
    void divide(int s){
    	vis[s] = true;
    	solve(s);
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(vis[po]) continue;
    		maxp[rt = 0] = all = siz[po];
    		getrt(po,0);
    		getrt(rt,0);
    		divide(rt);
    	}
    }
    int main()
    {
    	cin>>n;
    	for(int i = 1;i <= n - 1;i++){
    		scanf("%d%d%d",&u,&v,&w);
    		add(u,v,w);
    		add(v,u,w);
    	}
    	cin>>k;
    	maxp[rt = 0] = all = n;
    	getrt(1,0);
    	getrt(rt,0);
    	divide(rt);
    	cout<<ans<<endl;
    	return 0;
    }
    

      

    dsu on tree的一题:

    CF600 E. Lomsat gelral

    计算和计入同时进行(是否同时进行要根据题目判断),对于轻儿子要清空

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    const int MAXN = 1e5+7;
    int n, u, v;
    int c[MAXN];
    long long ans[MAXN],sum = 0;
    struct EDGE{
    	int to,next;
    }edge[MAXN*2];
    int head[MAXN],tot = 0;
    void add(int u,int v){
    	tot++;
    	edge[tot].to = v;
    	edge[tot].next = head[u];
    	head[u] = tot;
    }
    int siz[MAXN],deep[MAXN],son[MAXN],fa[MAXN];
    void dfs1(int s,int f){
    	siz[s] = 1;deep[s] = deep[f] + 1,fa[s] = f;
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(po == fa[s]) continue;
    		dfs1(po,s);
    		siz[s] +=siz[po];
    		if(siz[po]>siz[son[s]]) son[s] = po; 
    	}
    }
    int cnt[MAXN],ma = 0;
    void count(int s){
    	cnt[c[s]]++;
    	if(cnt[c[s]] > ma){
    		ma = cnt[c[s]];
    		sum = c[s];
    	}
    	else if( cnt[c[s]] == ma) sum += c[s];
    }
    void calc(int s){
    	count(s);
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(po == fa[s]) continue;
    		calc(po);
    	}
    }
    void clear(int s){
    	sum = ma = 0;
    	cnt[c[s]]--;
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(po == fa[s]) continue;
    		clear(po);
    	}
    }
    void DSU_ON_TREE(int s,bool is_heavy){
    	for(int i = head[s];i;i=edge[i].next){
    		int po = edge[i].to;
    		if(po == son[s] || po == fa[s]) continue;
    		DSU_ON_TREE(po,0);//求轻儿子 (计算轻儿子并清空)
    	}
    	if(son[s]) {
    		DSU_ON_TREE(son[s],1);//求重儿子 (计算重儿子不清空)
    	}
    	for(int i = head[s];i;i = edge[i].next){//计算轻儿子 
    		int po = edge[i].to;
    		if(po == son[s] || po == fa[s]) continue;
    		calc(po);
    	}
    	count(s);//计算根节点 
    	ans[s] = sum;
    	if(!is_heavy) clear(s);//不是重儿子,清空 
    	return;
    }
    int main()
    {
    	cin>>n;
    	for(int i = 1;i <= n;i++) scanf("%d",&c[i]),head[i] = 0;
    	for(int i = 1;i <= n - 1;i++) {
    		scanf("%d%d",&u,&v);
    		add(u,v);
    		add(v,u);
    	}
    	dfs1(1,0);
    	DSU_ON_TREE(1,1);
    	for(int i = 1;i <= n;i++){
    		printf("%lld ",ans[i]);
    	}
    	printf("
    ");
    	return 0;
    }
    

      

  • 相关阅读:
    KindEditor粘贴word图片且图片文件自动上传功能
    umeditor粘贴word图片且图片文件自动上传功能
    百度Web编辑器粘贴word图片且图片文件自动上传功能
    PHP大文件上传支持断点上传解决方案
    PHP大文件上传支持断点上传教程
    matlab函数——shading函数
    Matlab griddata函数功能介绍
    戴尔 SE2416HM
    visio中如何旋转形状
    axios的封装与异常处理(async/await)
  • 原文地址:https://www.cnblogs.com/ruanbaitql/p/14825316.html
Copyright © 2020-2023  润新知