题意:给一棵树,每次给两个节点间的所有节点发放第k种东西,问最后每个节点拿到的最多的东西是哪种。
解法:解决树的路径上的修改查询问题一般用到的是树链剖分+线段树,以前不会写,后来学了一下树链剖分,感觉也不是很难,就是把整个数分成很多链,然后一条重链上的点在线段树中位置是连续的,这样使得更新和查询时更加便利。
这个题目中线段树应该维护的是种类,每次对u-v发放k时,可以让u处+k,v+1处-k,把这些都离线存起来,然后枚举1~n,分别把自己该做的操作都做了,然后统计的时候tree[1].type就是该点的type。
这题是借鉴别人的代码写的,总算对树链剖分的题有所了解了。
还有在HDU交C++会爆栈,要加一个扩栈语句,不想加交G++也可以。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <vector> using namespace std; #define N 100007 int siz[N]; //子树大小 int son[N]; //重儿子 int dep[N]; //深度 int pos[N]; //在线段树中的位置 int apos[N]; //线段树中位置对应的点 int Top[N]; //所在重链的祖先 int fa[N]; //父节点 int ans[N]; //答案 int head[2*N],tot,POS,n,m; struct Edge { int v,next; }G[2*N]; struct Tree { int num,type; }tree[4*N]; struct node { int u,v,z; node(){} node(int _u,int _v,int _z):u(_u),v(_v),z(_z){} }; vector<node> com; vector<int> Q[N]; void init() { POS = tot = 0; memset(head,-1,sizeof(head)); memset(son,-1,sizeof(son)); com.clear(); for(int i=0;i<=n+1;i++) Q[i].clear(); } void addedge(int u,int v) { G[tot].v = v, G[tot].next = head[u], head[u] = tot++; G[tot].v = u, G[tot].next = head[v], head[v] = tot++; } void pushup(int rt) { if(tree[2*rt].num >= tree[2*rt+1].num) tree[rt].type = tree[2*rt].type; else tree[rt].type = tree[2*rt+1].type; tree[rt].num = max(tree[2*rt].num,tree[2*rt+1].num); } void build(int l,int r,int rt) { tree[rt].num = 0; if(l == r) { tree[rt].type = l; return; } int mid = (l+r)/2; build(l,mid,2*rt); build(mid+1,r,2*rt+1); pushup(rt); } void update(int l,int r,int pos,int val,int rt) { if(l == r) { tree[rt].num += val; return; } int mid = (l+r)/2; if(pos <= mid) update(l,mid,pos,val,2*rt); else update(mid+1,r,pos,val,2*rt+1); pushup(rt); } void dfs(int u,int f) { dep[u] = dep[f]+1; siz[u] = 1; for(int i=head[u];i!=-1;i=G[i].next) { int v = G[i].v; if(v == f) continue; fa[v] = u; dfs(v,u); if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v; siz[u] += siz[v]; } } void dfs2(int u,int father) { pos[u] = ++POS; apos[POS] = u; Top[u] = father; if(son[u] != -1) dfs2(son[u],father); //有重儿子优先dfs for(int i=head[u];i!=-1;i=G[i].next) { int v = G[i].v; if(v != fa[u] && v != son[u]) dfs2(v,v); } } void getcom(int u,int v,int z) { int fx = Top[u], fy = Top[v]; while(fx != fy) { if(dep[fx] < dep[fy]) { swap(u,v); swap(fx,fy); } com.push_back(node(pos[fx],pos[u],z)); u = fa[fx]; fx = Top[u]; } if(dep[u] > dep[v]) swap(u,v); com.push_back(node(pos[u],pos[v],z)); } int main() { int i,j,maxi,u,v,z; while(scanf("%d%d",&n,&m)!=EOF && n+m) { init(); for(i=1;i<n;i++) { scanf("%d%d",&u,&v); addedge(u,v); } dep[1] = 0; dfs(1,1); dfs2(1,1); maxi = 1; while(m--) { scanf("%d%d%d",&u,&v,&z); getcom(u,v,z); maxi = max(maxi,z); } int SIZE = com.size(); for(i=0;i<SIZE;i++) { int u = com[i].u, v = com[i].v, z = com[i].z; Q[u].push_back(z); Q[v+1].push_back(-z); } build(1,maxi,1); for(i=1;i<=n;i++) { sort(Q[i].begin(),Q[i].end()); int sz = Q[i].size(); for( j=0;j<sz;j++) { int p = Q[i][j]; if(p < 0) update(1,maxi,-p,-1,1); else update(1,maxi,p,1,1); } ans[apos[i]] = tree[1].type; if(tree[1].num == 0) ans[apos[i]] = 0; } for(i=1;i<=n;i++) printf("%d\n",ans[i]); } return 0; }