BZOJ3307: 雨天的尾巴
【传送门:BZOJ3307】
简要题意:
给出一棵n个点的树,有m个操作
每个操作输入x,y,z,表示x到y的路径上的所有点都放一个编号为z的物品
最后输出每个点存放最多的物品是哪个(如果有存放数量相同的物品,输出编号小的)
题解:
对于每种操作相当于区间增值,那就树上差分,而因为物品不同,所以每个点都用主席树来维护
主席树上的叶子节点为物品,点权为出现的数量
然后求答案的时候从叶子节点向上合并主席树就行了,因为合并之后的主席树的叶子节点的点权肯定都是>=0
所以在合并之后再更新最大值就行了
PS:这题有点小卡空间
参考代码:
#include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #define Maxn 110000 using namespace std; struct node{int x,y,next;}a[Maxn*2];int len,last[Maxn]; void ins(int x,int y){a[++len]=(node){x,y,last[x]};last[x]=len;} int f[Maxn][21],dep[Maxn]; void dfs(int x) { for(int i=1;dep[x]>=(1<<i);i++) { f[x][i]=f[f[x][i-1]][i-1]; } for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y==f[x][0]) continue; f[y][0]=x; dep[y]=dep[x]+1; dfs(y); } } int LCA(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int i=20;i>=0;i--) { if(dep[x]-dep[y]>=(1<<i)) x=f[x][i]; } if(x==y) return x; for(int i=20;i>=0;i--) { if(dep[x]>=(1<<i)&&f[x][i]!=f[y][i]) { x=f[x][i];y=f[y][i]; } } return f[x][0]; } struct trnode{int lc,rc,mx;}tr[Maxn*60];int rt[Maxn],tot; void update(int u) { int lc=tr[u].lc,rc=tr[u].rc; if(lc!=0&&rc!=0) { if(tr[lc].mx>=tr[rc].mx) tr[u].mx=tr[lc].mx; else tr[u].mx=tr[rc].mx; } else if(lc!=0) tr[u].mx=tr[lc].mx; else if(rc!=0) tr[u].mx=tr[rc].mx; } void add(int &u,int x,int d,int l,int r) { if(u==0) u=++tot; if(l==r) { tr[u].mx+=d; return ; } int mid=(l+r)/2; if(x<=mid) add(tr[u].lc,x,d,l,mid); else add(tr[u].rc,x,d,mid+1,r); update(u); } void Merge(int &u1,int u2,int l,int r) { if(u1==0){u1=u2;return ;} if(u2==0) return ; if(l==r) { tr[u1].mx+=tr[u2].mx; return ; } int mid=(l+r)/2; Merge(tr[u1].lc,tr[u2].lc,l,mid); Merge(tr[u1].rc,tr[u2].rc,mid+1,r); update(u1); } struct query{int x,y,p,z;}Q[Maxn];int to[Maxn],p; bool cmp(query n1,query n2){return n1.z<n2.z;} int ans[Maxn]; int gett(int u,int l,int r) { if(l==r) return l; int lc=tr[u].lc,rc=tr[u].rc,mid=(l+r)/2; if(tr[lc].mx>=tr[rc].mx) return gett(lc,l,mid); else return gett(rc,mid+1,r); } void solve(int x) { for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y==f[x][0]) continue; solve(y); Merge(rt[x],rt[y],1,p); } if(tr[rt[x]].mx<=0) ans[x]=0; else ans[x]=to[gett(rt[x],1,p)]; } int main() { int n,m; scanf("%d%d",&n,&m); len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } dep[1]=1;f[1][0]=0;dfs(1); memset(rt,0,sizeof(rt));tot=0; for(int i=1;i<=m;i++) scanf("%d%d%d",&Q[i].x,&Q[i].y,&Q[i].z); sort(Q+1,Q+m+1,cmp); p=1;Q[1].p=p;to[1]=Q[1].z; for(int i=2;i<=m;i++) { if(Q[i].z!=Q[i-1].z) p++; Q[i].p=p;to[p]=Q[i].z; } for(int i=1;i<=m;i++) { int x=Q[i].x,y=Q[i].y,z=Q[i].p; int lca=LCA(x,y); add(rt[x],z,1,1,p);add(rt[y],z,1,1,p);add(rt[lca],z,-1,1,p); if(f[lca][0]!=0) add(rt[f[lca][0]],z,-1,1,p); } solve(1); for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚