BZOJ3307: 雨天的尾巴

【傳送門:BZOJ3307


簡要題意:

  給出一棵n個點的樹,有m個操做
php

  每一個操做輸入x,y,z,表示x到y的路徑上的全部點都放一個編號爲z的物品node

  最後輸出每一個點存放最多的物品是哪一個(若是有存放數量相同的物品,輸出編號小的)spa


題解:

  對於每種操做至關於區間增值,那就樹上差分,而由於物品不一樣,因此每一個點都用主席樹來維護
code

  主席樹上的葉子節點爲物品,點權爲出現的數量blog

  而後求答案的時候從葉子節點向上合併主席樹就好了,由於合併以後的主席樹的葉子節點的點權確定都是>=0get

  因此在合併以後再更新最大值就好了string

  PS:這題有點小卡空間it


參考代碼:

#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;
}
相關文章
相關標籤/搜索