给你一棵树,然后有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; }