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;
}

 

posted @ 2018-11-19 13:03  Star_Feel  阅读(165)  评论(0编辑  收藏  举报