P4556 [Vani有约会]雨天的尾巴
标签
相关讨论
进入讨论版推荐题目
题目背景
深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。
题目描述
首先村落里的一共有n座房屋,并形成一个树状结构。然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
输入格式
第一行两个正整数n,m,含义如题目所示。
接下来n-1行,每行两个数(a,b),表示(a,b)间有一条边。
再接下来m行,每行三个数(x,y,z),含义如题目所示。
输出格式
n行,第i行一个整数,表示第i座房屋里存放的最多的是哪种救济粮,如果有多种救济粮存放次数一样,输出编号最小的。
如果某座房屋里没有救济粮,则对应一行输出0。
输入输出样例
输入 #1
5 3 1 2 3 1 3 4 5 3 2 3 3 1 5 2 3 3 3
输出 #1
2 3 3 0 2
说明/提示
对于20%的数据,1 <= n, m <= 100
对于50%的数据,1 <= n, m <= 2000
对于100%的数据,1 <= n, m <= 100000, 1 <= a, b, x, y <= n, 1 <= z <= 100000
这题很明显是一道树剖题 但是可以用线段树合并来解决
显然每个点维护一个权值线段树 可以直接输出做多的粮食是什么
因为线段树合并自下而上类似一个求前缀和的过程 所以可以利用差分数组 点更新
在u+1 v+1 lca(u,v)-1 falca(u,v)-1 即可
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// const int N=6000005; int T[N<<2],lson[N<<2],rson[N<<2],maxx[N<<2],t[N<<2],ncnt,n,m,nn,ans[N]; void up(int pos) { if(maxx[lson[pos]]>=maxx[rson[pos]]) maxx[pos]=maxx[lson[pos]],t[pos]=t[lson[pos]]; else maxx[pos]=maxx[rson[pos]],t[pos]=t[rson[pos]]; } void upnode(int x,int v,int l,int r,int &pos) { if(!pos)pos=++ncnt; if(l==r){t[pos]=l;maxx[pos]+=v;return ;} int m=(l+r)>>1; if(x<=m)upnode(x,v,l,m,lson[pos]); else upnode(x,v,m+1,r,rson[pos]); up(pos); } int Merge(int a,int b,int l,int r) { if(!a)return b; if(!b)return a; if(l==r) { maxx[a]+=maxx[b]; t[a]=l; return a; } int m=(l+r)>>1; lson[a]=Merge(lson[a],lson[b],l,m); rson[a]=Merge(rson[a],rson[b],m+1,r); up(a); return a; } //////////////////////// int fa[N],top[N],siz[N],son[N],dep[N],pos,head[N]; struct Edge{int to,nex;}edge[N]; void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;} void dfs1(int x,int f) { fa[x]=f;dep[x]=dep[f]+1;siz[x]=1;son[x]=0; for(int i=head[x];i;i=edge[i].nex) { int v=edge[i].to;if(v==f)continue; dfs1(v,x);siz[x]+=siz[v]; if(siz[son[x]]<siz[v])son[x]=v; } } void dfs2(int x,int topf) { top[x]=topf; if(son[x])dfs2(son[x],topf); for(int i=head[x];i;i=edge[i].nex) { int v=edge[i].to;if(v==fa[x]||v==son[x])continue; dfs2(v,v); } } int Lca(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); x=fa[top[x]]; } return dep[x]<dep[y]?x:y; } void dfs3(int x) { for(int i=head[x];i;i=edge[i].nex)if(dep[edge[i].to]>dep[x]) dfs3(edge[i].to),T[x]=Merge(T[x],T[edge[i].to],1,nn); if(maxx[T[x]])ans[x]=t[T[x]]; } int L[N],R[N],V[N]; int main() { cin>>n>>m; rep(i,1,n-1) { int x,y;scanf("%d%d",&x,&y); add(x,y);add(y,x); } rep(i,1,n)T[i]=i,++ncnt; dfs1(1,0); dfs2(1,1); rep(i,1,m) { scanf("%d%d%d",&L[i],&R[i],&V[i]); nn=max(nn,V[i]); } rep(i,1,m) { int lca=Lca(L[i],R[i]); upnode(V[i],1,1,nn,T[L[i]]); upnode(V[i],1,1,nn,T[R[i]]); upnode(V[i],-1,1,nn,T[lca]); if(fa[lca])upnode(V[i],-1,1,nn,T[fa[lca]]); } dfs3(1); rep(i,1,n) printf("%d ",ans[i]); return 0; }
也可以用树链剖分差分来做
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// const int N=1e5+100; int maxx[N<<2],t[N<<2],pos,head[N],ans[N],n,m,a,b,c,pre[N]; vector<int>table[N]; void up(int pos) { if(maxx[pos<<1]>=maxx[pos<<1|1]) maxx[pos]=maxx[pos<<1],t[pos]=t[pos<<1]; else maxx[pos]=maxx[pos<<1|1],t[pos]=t[pos<<1|1]; } void build(int l,int r,int pos) { if(l==r){maxx[pos]=0;t[pos]=l;return;} int m=(l+r)>>1; build(l,m,pos<<1);build(m+1,r,pos<<1|1); up(pos); } void upnode(int x,int v,int l,int r,int pos) { if(l==r){maxx[pos]+=v;return ;} int m=(l+r)>>1; if(x<=m)upnode(x,v,l,m,pos<<1); else upnode(x,v,m+1,r,pos<<1|1); up(pos); } int son[N],siz[N],fa[N],top[N],id[N],ncnt,dep[N]; struct Edge{int to,nex;}edge[N<<1]; void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;} void dfs1(int x,int f) { fa[x]=f;dep[x]=dep[f]+1;son[x]=0;siz[x]=1; for(int i=head[x];i;i=edge[i].nex) { int v=edge[i].to;if(v==f)continue; dfs1(v,x);siz[x]+=siz[v]; if(siz[son[x]]<siz[v])son[x]=v; } } void dfs2(int x,int topf) { top[x]=topf;id[x]=++ncnt;pre[ncnt]=x; if(son[x])dfs2(son[x],topf); for(int i=head[x];i;i=edge[i].nex) { int v=edge[i].to;if(v==son[x]||v==fa[x])continue; dfs2(v,v); } } void UPsum(int x,int y,int v) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); table[id[top[x]]].push_back(v);table[id[x]+1].push_back(-v); x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); table[id[x]].push_back(v);table[id[y]+1].push_back(-v); } int main() { scanf("%d%d",&n,&m); rep(i,1,n-1) { scanf("%d%d",&a,&b);add(a,b);add(b,a); } dfs1(1,1); dfs2(1,1); while(m--) { scanf("%d%d%d",&a,&b,&c); UPsum(a,b,c); } build(1,1e5,1); rep(i,1,n) { for(auto v:table[i]) if(v>0)upnode(v,1,1,1e5,1); else upnode(-v,-1,1,1e5,1); if(maxx[1]) ans[pre[i]]=t[1]; else ans[pre[i]]=0; } rep(i,1,n)printf("%d ",ans[i]); return 0; }