[BZOJ]3307: 雨天的尾巴 线段树合并+树上差分
2018-01-07 16:59
531 查看
Description
N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。
N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。
题解:
这题真的很有必要写一写……做法是挺常规的套路,由于是最后才询问,所以可以每个点开一个线段树,然后树上差分(确保点数只有nlogn个),最后线段树合并一次就行了。但是有个以前没有遇到过的问题,因为是差分,所以有可能有些点虽然有信息,但是它的root编号为0,这样最后合并的时候就会出现多个点的root编号一样的问题,解决方法是一开始就给每个root一个编号。代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define pa pair<int,int> const int Maxn=100010; const int inf=2147483647; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f; } struct O{int x,y,z;}q[Maxn]; struct lsh{int x,id;}Z[Maxn]; bool cmp(lsh a,lsh b){return a.x<b.x;} int n,m,fa[Maxn][20],dep[Maxn],yl[Maxn]; struct Edge{int y,next;}e[Maxn<<1]; int len=0,last[Maxn]; void ins(int x,int y){int t=++len;e[t].y=y;e[t].next=last[x];last[x]=t;} void dfs(int x,int f) { fa[x][0]=f;dep[x]=dep[f]+1; for(int i=1;(1<<i)<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=last[x];i;i=e[i].next) { int y=e[i].y; if(y==f)continue; dfs(y,x); } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=18;i>=0;i--) if((1<<i)<=dep[x]-dep[y])x=fa[x][i]; if(x==y)return x; for(int i=18;i>=0;i--) if(dep[x]>=(1<<i)&&fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int root[Maxn],tot=0; int lc[Maxn*55],rc[Maxn*55],mx[Maxn*55],num[Maxn*55]; void up(int u) { if(!rc[u]||mx[lc[u]]>=mx[rc[u]])mx[u]=mx[lc[u]],num[u]=num[lc[u]]; else mx[u]=mx[rc[u]],num[u]=num[rc[u]]; } void insert(int &u,int l,int r,int p,int x) { if(!u)u=++tot; if(l==r){mx[u]+=x;num[u]=l;return;} int mid=l+r>>1; if(p<=mid)insert(lc[u],l,mid,p,x); else insert(rc[u],mid+1,r,p,x); up(u); } void merge(int &u1,int u2,int l,int r) { if(!u1){u1=u2;return;} if(!u2)return; if(l==r){mx[u1]+=mx[u2];return;} int mid=l+r>>1; merge(lc[u1],lc[u2],l,mid); merge(rc[u1],rc[u2],mid+1,r); up(u1); } int cnt; void DFS(int x) { for(int i=last[x];i;i=e[i].next) { int y=e[i].y; if(y==fa[x][0])continue; DFS(y); merge(root[x],root[y],1,cnt); } } int main() { n=read(),m=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); ins(x,y);ins(y,x); } dep[0]=-1;dfs(1,0); for(int i=1;i<=m;i++)q[i].x=read(),q[i].y=read(),Z[i].x=read(),Z[i].id=i; sort(Z+1,Z+1+m,cmp); cnt=0;Z[0].x=-1; for(int i=1;i<=m;i++)q[Z[i].id].z=((Z[i].x==Z[i-1].x)?cnt:++cnt),yl[cnt]=Z[i].x; for(int i=1;i<=n;i++)root[i]=++tot; for(int i=1;i<=m;i++) { int x=q[i].x,y=q[i].y,z=q[i].z,lca=LCA(x,y); insert(root[x],1,cnt,z,1); insert(root[y],1,cnt,z,1); insert(root[lca],1,cnt,z,-1); if(fa[lca][0])insert(root[fa[lca][0]],1,cnt,z,-1); } DFS(1); for(int i=1;i<=n;i++) { if(!mx[root[i]])puts("0"); else printf("%d\n",yl[num[root[i]]]); } }
相关文章推荐
- BZOJ_3307_雨天的尾巴_线段树合并+树上差分
- 【BZOJ3307】雨天的尾巴-线段树合并+树上差分
- BZOJ 3307: 雨天的尾巴 线段树合并 树上差分
- bzoj 3307: 雨天的尾巴【树剖lca+树上差分+线段树合并】
- [BZOJ3307][线段树合并]雨天的尾巴
- BZOJ3307 雨天的尾巴 (树链剖分 线段树合并 dfs相关)
- bzoj 3307: 雨天的尾巴 (线段树合并+LCA)
- [bzoj3307]雨天的尾巴_线段树合并
- BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )
- 【bzoj3307】雨天的尾巴 权值线段树合并
- 【BZOJ3307】雨天的尾巴 线段树合并
- bzoj 3307: 雨天的尾巴 线段树
- [BZOJ3307][雨天的尾巴][树链剖分+线段树]
- BZOJ 3307 雨天的尾巴 线段树
- 【BZOJ3307】雨天的尾巴(树链剖分+树上差分+线段树)
- BZOJ 3307 雨天的尾巴 树上差分+lca+权值线段树合并
- [bzoj3307]雨天的尾巴【线段树】
- BZOJ3307 雨天的尾巴
- [ 树上启发式合并 线段树 单调栈 ] BZOJ5040
- bzoj3307 雨天的尾巴