codeforces 192E Fools and Roads

给你一棵树,然后有m个操作,每个操作有两个数 a  b,表示给从a到b的简单路径上的边权都加1,最后要你输出每条边的边权

解法1:dfs

用树链剖分做的话就是很裸的题目了,但是这道题没有让你对路径上的边权进行求和等操作,只是要你在最后输出每条边的边权,所以有一种更加简便的方法

对于一个操作 a  b  我们只需用个cnt数组标记一下cnt[a]++  cnt[b]++   cnt[lca(a,b)] -= 2,统计某条边被经过了多少次的时候只需要统计一下子树的cnt值之和即可

简单说明一下吧,如果子树中有两个点的lca也在子树中,那么这两个点之间的路径就不会经过这条边(cnt[lca]-=2),求子树 的cnt和时已经消掉了,相当于加上了一个-2 了



解法二:  线段树

来自http://hi.baidu.com/pearfish16/item/92e62fdb7ffc8617d78ed0a0

 

维护DFS序...具体就是记录每条边进栈、出栈的时间,出栈用负数表示,比如

 1 -1 2 3 4 -4 5 6 -6 7 -7 -5 8 9 -9 -8 -3 10 -10 -2

这样每次给一条链加1,就是给连续的一段数加1。那些不在链中的边,必然它和它的相反数的位置都被加了1,等

 

于没有计算。最后对于第i条边,答案就是a[i的位置]-a[(-i)的位置]。

怎么找两个点之间的路径所对应的区间是个大问题,想了好久想不出来,要不算了吧,正当我准备放弃的时候突然想到可以分别找到从LCA到两个点的路径所对应的区间,我的做法是update 从 lca的第一个出边分别到 u  v的入边所对应的区间,这样子可能会更新多余的,时间上会慢点,不过复杂度是过的去的



解法三:树链剖分 or  动态树,代码比较长。。。。就不贴了



解法一

#include<cstdio>
#include<cstring>
#include<set>
#include<string>
#include<iostream>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
#include<time.h>
#include<queue>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn  =  100010;
#define lowbit(x) ((x)&(-(x)))
#define sqr(x) ((x)*(x))
#define PB push_back
#define MP make_pair
typedef unsigned long long ULL;
typedef long long lld;
typedef vector<int> VI;
typedef pair<int,int> II;
const int POW = 17;
int p[maxn][POW];
VI edge[maxn],ee[maxn];
int cnt[maxn];
int dep[maxn];
void dfs(int u,int f)
{
	dep[u]=dep[f]+1;
	for(int i=0;i<edge[u].size();i++)
	{
		int v=edge[u][i];
		if(v==f) continue;
		p[v][0]=u;
		for(int j=1;j<POW;j++) p[v][j]=p[p[v][j-1]][j-1];
		dfs(v,u);
	}
}
int LCA(int a,int b)
{
    if(dep[a] > dep[b]) swap(a,b);
	if(dep[a] < dep[b])  {
		int del=dep[b]-dep[a];
		for(int i=0;i<POW;i++) if(del&(1<<i)) b=p[b][i];
	}
	if(a != b) {
		for(int i=POW-1;i>=0;i--)
			if(p[a][i]!=p[b][i])
				a=p[a][i],b=p[b][i];
			a=p[a][0],b=p[b][0];
	}
	return a;
}
int ans[maxn];
int la[maxn];
bool vis[maxn];
int solve(int u,int edge_num)
{
	vis[u]=true;
	int sum=0;
	for(int i=0;i<edge[u].size();i++)
	{
          int v=edge[u][i];
		  if(vis[v]) continue;
		  sum+=solve(v,ee[u][i]);
	}
	sum+=cnt[u];
	return ans[edge_num]=sum;
}
int main()
{
	int n,u,v;
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		edge[u].push_back(v);
		edge[v].push_back(u);
		ee[u].push_back(i);
		ee[v].push_back(i);
	}int m;
	dfs(1,0);
	scanf("%d",&m);
    for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		cnt[u]++;cnt[v]++;
		cnt[LCA(u,v)] -= 2;
	}
	solve(1,0);
	for(int i=1;i<n;i++) printf("%d ",ans[i]);
	return 0;
}


解法二

#include<cstdio>
#include<cstring>
#include<set>
#include<string>
#include<iostream>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
#include<time.h>
#include<queue>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define sqr(x) ((x)*(x))
#define PB push_back
#define MP make_pair
typedef vector<int> VI;
typedef vector<string> VS;
typedef pair<int,int> PII;
const int maxn  =  100010;
VI edge[maxn],ee[maxn],EE[maxn];
int L[maxn],R[maxn],up[maxn],down[maxn];
int tot;
int p[maxn][17];
int dep[maxn];
void dfs(int u,int f,int edge_num)
{
	dep[u]=dep[f]+1;
	up[u]=edge_num;
	L[edge_num] = ++tot;
	for(int i=0;i<edge[u].size();i++)
	{
		int v=edge[u][i];
		if(v==f) continue;
		p[v][0]=u;
		for(int j=1;j<17;j++) p[v][j]=p[p[v][j-1]][j-1];
		EE[u].push_back(ee[u][i]);
		dfs(v,u,ee[u][i]);
	}
	R[edge_num] = ++tot;
}
int LCA(int a,int b)
{
	if(dep[a] > dep[b]) swap(a,b);  
    if(dep[a] < dep[b])  {  
        int del=dep[b]-dep[a];  
        for(int i=0;i<17;i++) if(del&(1<<i)) b=p[b][i];  
    }  
    if(a != b) {  
        for(int i=17-1;i>=0;i--)  
            if(p[a][i]!=p[b][i])  
                a=p[a][i],b=p[b][i];  
            a=p[a][0],b=p[b][0];  
    }  
    return a;  
}
int sum[200010<<2],add[200010<<2];
inline void pushup(int rt) 
{
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
inline void pushdown(int rt,int l,int r)
{
	int m=l+r>>1;
	if(add[rt])
	{
		add[rt<<1] += add[rt];
		add[rt<<1|1] += add[rt];
		sum[rt<<1] += add[rt]*(m-l+1);
		sum[rt<<1|1] += add[rt]*(r-m);
		add[rt]=0;
	}
}
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
void update(int L,int R,int val,int l,int r,int rt)
{
	if(L <= l && r <= R) 
	{
		sum[rt]+=val*(r-l+1);
		add[rt]+=val;
		return ;
	}
	pushdown(rt,l,r);
	int m=l+r>>1;
	if(L <= m) update(L,R,val,lson);
	if(R > m) update(L,R,val,rson);
	pushup(rt);
}
int query(int p,int l,int r,int rt)
{
	if(l==r) return sum[rt];
	pushdown(rt,l,r);
	int m=l+r>>1;
    if(p<=m) return query(p,lson);
	return query(p,rson);
}
int ans[200010];
int main()
{
	int n,u,v,i,j,m;
	scanf("%d",&n);
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		edge[u].push_back(v);
		edge[v].push_back(u);
		ee[u].push_back(i);
		ee[v].push_back(i);
	}
	dfs(1,0,0);
	scanf("%d",&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		if(u==v) continue;
        int lca=LCA(u,v);
        if(lca!=u && lca!=v){
			update(L[*EE[lca].begin()],L[up[u]],1,1,tot,1);
			update(L[*EE[lca].begin()],L[up[v]],1,1,tot,1);
		} else if(lca==u) {
			update(L[*EE[lca].begin()],L[up[v]],1,1,tot,1);
		}  else {
			update(L[*EE[lca].begin()],L[up[u]],1,1,tot,1);
		}
	}
	for(i=1;i<=tot;i++)  ans[i]=query(i,1,tot,1);
	for(i=1;i<n;i++) 	printf("%d ",ans[L[i]]-ans[R[i]]);
	return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值