【BZOJ3307】雨天的尾巴
Description
N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。
Input
第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题
Output
输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有多种物品的数量一样,输出编号最小的。如果某个点没有物品则输出0
题解:看到题直接的想法就是树套树,但是由于可以离线,我们可以直接差分。
具体地,我们对于每个点都维护一棵权值线段树,然后将标记差分,最后将每个节点的线段树与父亲节点的线段树合并即可。
建议:在一开始的时候就为每个点创建一个rt节点。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int maxn=100010; int inf=1000000000; int n,m,cnt,tot; int to[maxn<<1],next[maxn<<1],head[maxn],fa[19][maxn],dep[maxn],rt[maxn],p[maxn],ref[maxn]; int v[maxn*50],s[maxn*50],ls[maxn*50],rs[maxn*50]; struct node { int a,b,c; }q[maxn]; bool cmp(node a,node b) { return a.c<b.c; } int rd() { int ret=0; char gc=getchar(); while(gc<'0'||gc>'9') gc=getchar(); while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret; } void add(int a,int b) { to[++cnt]=b,next[cnt]=head[a],head[a]=cnt; } void dfs(int x) { p[++p[0]]=x; for(int i=head[x];i;i=next[i]) if(to[i]!=fa[0][x]) fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]); } int lca(int a,int b) { if(dep[a]<dep[b]) swap(a,b); for(int i=18;i>=0;i--) if(dep[fa[i][a]]>=dep[b]) a=fa[i][a]; if(a==b) return a; for(int i=18;i>=0;i--) if(fa[i][a]!=fa[i][b]) a=fa[i][a],b=fa[i][b]; return fa[0][a]; } void pushup(int x) { v[x]=max(v[ls[x]],v[rs[x]]); s[x]=(v[ls[x]]>=v[rs[x]])?s[ls[x]]:s[rs[x]]; } void insert(int &x,int a,int b,int l,int r) { if(!x) x=++tot; if(l==r) { v[x]+=b,s[x]=ref[l]; return ; } int mid=l+r>>1; if(a<=mid) insert(ls[x],a,b,l,mid); else insert(rs[x],a,b,mid+1,r); pushup(x); } void merge(int &a,int b,int l,int r) { if(!b) return ; if(!a) { a=b; return ; } if(l==r) { v[a]+=v[b]; return ; } int mid=l+r>>1; merge(ls[a],ls[b],l,mid),merge(rs[a],rs[b],mid+1,r); pushup(a); } int main() { int i,j,a,b,c,d; n=rd(),m=rd(); for(i=1;i<=n;i++) rt[i]=++tot; for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a); dep[1]=1,dfs(1); for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]]; for(i=1;i<=m;i++) q[i].a=rd(),q[i].b=rd(),q[i].c=rd(); sort(q+1,q+m+1,cmp); for(d=0,i=1;i<=m;i++) { a=q[i].a,b=q[i].b,c=lca(a,b); if(q[i].c>q[i-1].c) ref[++d]=q[i].c; insert(rt[a],d,1,0,m),insert(rt[b],d,1,0,m),insert(rt[c],d,-1,0,m); if(c!=1) insert(rt[fa[0][c]],d,-1,0,m); } for(i=n;i>1;i--) merge(rt[fa[0][p[i]]],rt[p[i]],0,m); for(i=1;i<=n;i++) printf("%d ",s[rt[i]]); return 0; }