zoukankan      html  css  js  c++  java
  • [CF191](Fools and Roads)

    题意 : 给你一棵树,然后给你m对点,将每对点之间的最短路径上每条边权值+1,求操作完成后每条边的权值

    solution:树上差分(其实如果你是数据结构大师的话也可以用树链剖分做)

    树上差分的板子是这样的:
    设差分数组p,对于路径s->t,p[s]++,p[t]++,p[lca(s,t)]--,p[fa[lca[(s,t)]]]--;

    然后一个点的子树内差分数组值之和即为该点被覆盖的次数
    然而这题要求我们处理边

    那么我们有两种方法

    一种是对于一条边,新建一个点代表这条边,由该点向边的两个端点连边

    暴力但很无脑

    另一种是用一条边的两个端点中深度较大的端点代表这条边

    但此时原来的差分操作会出锅,要改为p[s]++,p[t]++,p[lca(s,t)]-=2(自己理解)

    贴代码(第一种方法,欧拉序ST表求LCA)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #define N 400050
    using namespace std;
    vector<int> G[N];
    int n,m;
    int dfn[N],pos[N],lg[N],dep[N];
    int id[N],ans[N];
    int st[35][N],cnt=0,plu[N],fa[N];
    void aux(int x,int ff) {
    	dfn[++cnt]=x,pos[x]=cnt,fa[x]=ff;
    	for(int i=0; i<G[x].size(); i++) {
    		int to=G[x][i];
    		if(to==ff)continue;
    		dep[to]=dep[x]+1;
    		aux(to,x);
    		dfn[++cnt]=x;
    		}
    	}
    int mn(int a,int b) {
    	return (dep[a]<dep[b])?a:b;
    	}
    void build() {
    	lg[0]=-1;
    	for(int i=1; i<=N-10; i++)lg[i]=lg[i>>1]+1;
    	for(int i=1; i<=cnt; i++)st[0][i]=dfn[i];
    	for(int i=1; i<=lg[cnt]; i++)
    		for(int r=1; r+(1<<i)<=cnt; r++)
    			st[i][r]=mn(st[i-1][r],st[i-1][r+(1<<(i-1))]);
    	}
    int lca(int a,int b) {
    	int x=pos[a],y=pos[b];
    	if(x>y)swap(x,y);
    	int p=lg[y-x+1];
    	return mn(st[p][x],st[p][y-(1<<p)+1]);
    	}
    void add_edge(int a,int b) {
    	G[a].push_back(b),G[b].push_back(a);
    	}
    void all_last(int x,int ff) {
    	for(int i=0; i<G[x].size(); i++) {
    		int to=G[x][i];
    		if(to==ff)continue;
    		all_last(to,x);
    		plu[x]+=plu[to];
    		}
    	if(id[x])ans[id[x]]=plu[x];
    	}
    int main() {
    	scanf("%d",&n);
    	for(int i=1; i<n; i++) {
    		int a,b;
    		scanf("%d%d",&a,&b);
    		add_edge(a,i+n);
    		add_edge(i+n,b);
    		id[i+n]=i;
    		}
    	aux(1,0);
    	build();
    	scanf("%d",&m);
    	for(int i=1; i<=m; i++) {
    		int a,b;
    		scanf("%d%d",&a,&b);
    		int poi=lca(a,b);
    		plu[fa[poi]]--;
    		plu[poi]--;
    		plu[a]++,plu[b]++;
    		}
    	all_last(1,0);
    	for(int i=1; i<n; i++)printf("%d ",ans[i]);
    	}
    
    
  • 相关阅读:
    每次VS code中添加新项目格式化就会失效
    Odoo14学习笔记(14) 设置记录规则
    Odoo14学习笔记(13) 用户组权限设置
    微信小程序学习笔记(6) 使用wx.navigateTo做页面跳转
    微信小程序学习笔记(5) 使用wx:for循环显示数据
    微信小程序学习笔记(4) 第三方库request promise使用
    微信小程序学习笔记(3) 第一版小程序发布
    微信小程序学习笔记(2) 图片不显示问题总结
    微信小程序学习笔记(1) 学习开始
    Odoo14学习笔记(12) 在Tree/View中增加自增序号
  • 原文地址:https://www.cnblogs.com/stepsys/p/10802586.html
Copyright © 2011-2022 走看看