bzoj3307雨天的尾巴(线段树合并)

Description

N个点,形成一个树状结构。有M次发放,每次选择两个点x,y
对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成
所有发放后,每个点存放最多的是哪种物品。

Input

第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题

Output

输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有
多种物品的数量一样,输出编号最小的。如果某个点没有物品
则输出0

我们首先可以树上差分一下贡献,然后线段树自下而上合并就好了.
(启发式合并应该更靠谱,然而我动态开点后并不会维护size,维护了反而可能MLE,最后暴力合并一发A了,只是卡了发评测...)

#include 
#include 
#include 
#define maxn 100005
#define maxx 200005
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline void read(int& x)
{   char c=getchar();x=0;int y=1;
    while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    x*=y;
}
const int VMAX=1e9;
inline int m_max(int x,int y){return x>y?x:y;}
int n,m,son[maxn],ssum[maxn],top[maxn],fa[maxn],dp[maxn],ans[maxn],num,hea[maxn];
struct road{int en,nex;}ro[maxx];
inline void add(int x,int y){ro[num].en=y;ro[num].nex=hea[x];hea[x]=num++;}
inline void dfs(int x,int y=0)
{   ssum[x]=1;fa[x]=y;dp[x]=dp[y]+1;
    for(int i=hea[x];i!=-1;i=ro[i].nex)
    {   int v=ro[i].en;
        if(v==y) continue;
        dfs(v,x);ssum[x]+=ssum[v];
        if(!son[x]||ssum[son[x]]inline void redfs(int x,int y=1)
{   top[x]=y;
    if(!son[x]) return;
    redfs(son[x],y);
    for(int i=hea[x];i!=-1;i=ro[i].nex)
    {   int v=ro[i].en;
        if(v!=fa[x]&&v!=son[x]) redfs(v,v);
    }
}
inline int flca(int x,int y)
{   int t1=top[x],t2=top[y];
    while(t1!=t2)
    {   if(dp[t1]std::swap(t1,t2),std::swap(x,y);
        x=fa[t1];t1=top[x];
    }
    if(dp[x]>dp[y]) std::swap(x,y);
    return x;
}
struct tree
{   tree *lch,*rch;int ma;
    tree():lch(NULL),rch(NULL),ma(0){}
    inline int mval(){return this?this->ma:0;}
    inline void mt(){this->ma=m_max(this->lch->mval(),this->rch->mval());}
}*root[maxn];
inline void update(tree*& now,int x,int l,int r,int z)
{   if(!now) now=new tree();
    if(l==r){now->ma+=z;return;}
    int mid=l+r>>1;
    if(x<=mid) update(now->lch,x,l,mid,z);
    else update(now->rch,x,mid+1,r,z);
    now->mt();
}
inline void merge(tree*& x,tree* y,int l,int r)
{   if(!y) return;if(!x){x=y;return;}
    if(l==r){x->ma+=y->ma;return;}
    int mid=l+r>>1;
    merge(x->lch,y->lch,l,mid);merge(x->rch,y->rch,mid+1,r);
    x->mt();
}
inline int dfs4(tree* x,int y,int l,int r)
{   if(!x) return 0;
    if(l==r) return l;
    int mid=l+r>>1;
    if(x->lch->mval()==y) return dfs4(x->lch,y,l,mid);
    else return dfs4(x->rch,y,mid+1,r);
}
inline void dfs3(int x,int y=0)
{   for(int i=hea[x];i!=-1;i=ro[i].nex)
    {   int v=ro[i].en;
        if(v==y) continue;
        dfs3(v,x);
        merge(root[x],root[v],1,VMAX);
    }
    if(root[x]->mval())
        ans[x]=dfs4(root[x],root[x]->mval(),1,VMAX);
}
int main()
{   read(n);read(m);int x=0,y=0,z=0;mem(hea,-1);
    for(int i=1;i1);redfs(1);
    for(int i=1;i<=m;++i)
    {   read(x);read(y);read(z);
        int tmp=flca(x,y);
        update(root[x],z,1,VMAX,1);
        update(root[y],z,1,VMAX,1);
        update(root[tmp],z,1,VMAX,-1);
        if(fa[tmp]) update(root[fa[tmp]],z,1,VMAX,-1);
    }
    dfs3(1);
    for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
    return 0;
}

你可能感兴趣的:(线段树,树上差分)