雨天的尾巴

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
范围
1<=N,M<=100000
1<=a,b,x,y<=N
1<=z<=10^9

如果在一个链上。
把操作(x,y,+1)拆成(x,r,+1)与(y+1,r,-1)。发现从左到右扫一遍,遍扫变统计前面的答案是与后面的询问无关的。
树上。。树链剖分拆成log个区间。把树拍成区间来做。。这题小细节比较多。。我估计要调一年的那种。
颜色编号最小,没有物品输出0。

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1e5+5;
const int INF=1e9+7;

struct edge{
    int to,next;
}e[MAXN<<1];

int head[MAXN],cnt=0;
inline void add(int u,int v){e[++cnt]=(edge){v,head[u]},head[u]=cnt;}

int fa[MAXN],size[MAXN],dep[MAXN],hson[MAXN];
void dfs1(int u,int father){
    fa[u]=father;
    size[u]=1;
    dep[u]=dep[father]+1;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v==father)continue;
        dfs1(v,u);
        size[u]+=size[v];
        if(!hson[u]||size[hson[u]]<size[v])hson[u]=v;
    }
}

int top[MAXN],id[MAXN],rl[MAXN],num=0;
void dfs2(int u,int tp){
    top[u]=tp;
    id[u]=++num;
    rl[num]=u;
    if(hson[u])dfs2(hson[u],tp);
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v==fa[u]||v==hson[u])continue;
        dfs2(v,v);
    }   
}

int tot=0;
struct query{
    int color,num;
};

vector<query>vec[MAXN];
map<int,int>ma,ma2;//ma  颜色->序号   ma2序号->颜色 
int ans[MAXN];

int maxv[MAXN<<2],who[MAXN<<2];
typedef pair<int,int>par;
struct xds{
    #define lson (o<<1)
    #define rson (o<<1|1)
    #define mp make_pair
    inline void pushup(int o){
        if(maxv[lson]==maxv[rson]){
            maxv[o]=maxv[lson];
            if(who[lson]<who[rson])who[o]=who[lson];
            else who[o]=who[rson];
        }
        else if(maxv[lson]>maxv[rson])maxv[o]=maxv[lson],who[o]=who[lson];
        else maxv[o]=maxv[rson],who[o]=who[rson];
    } 
    void build(int o,int l,int r){
        if(l==r){maxv[o]=0;who[o]=ma2[l];return;}
        int mid=l+r>>1;
        build(lson,l,mid);build(rson,mid+1,r);
        pushup(o);
    }
    void change(int o,int l,int r,int pos,int val){
        if(l==r){maxv[o]+=val;return;}
        int mid=l+r>>1;
        if(pos<=mid)change(lson,l,mid,pos,val);
        else change(rson,mid+1,r,pos,val);
        pushup(o);
    }
    par querymax(int o,int l,int r,int ql,int qr){
        if(ql<=l&&qr>=r)return mp(maxv[o],who[o]);
        int mid=l+r>>1;
        par ans=mp(-INF,0),t1,t2;
        if(ql<=mid)t1=querymax(lson,l,mid,ql,qr);
        if(qr>mid)t2=querymax(rson,mid+1,r,ql,qr);
        if(t1.first==t2.first){
            if(t1.second<t2.second)ans=t1;
            else ans=t2;
        }
        else if(t1.first<t2.first)ans=t1;
        else ans=t2;
        return ans;
    }
}T;

int lca(int x,int y,int c){
    int tx=top[x],ty=top[y];
    while(tx!=ty){
        if(dep[tx]<dep[ty]){
            vec[id[ty]].push_back((query){c,1});
            vec[id[y]+1].push_back((query){c,-1});
            y=fa[ty];
        }
        else {
            vec[id[tx]].push_back((query){c,1});
            vec[id[x]+1].push_back((query){c,-1});
            x=fa[tx];
        }
        tx=top[x],ty=top[y];
    }
    if(dep[x]<dep[y])swap(x,y); 
    vec[id[y]].push_back((query){c,1});
    vec[id[x]+1].push_back((query){c,-1});
    return y;
}


void getans(int n){
    for(int i=1;i<=n;i++){
        for(int j=0;j<vec[i].size();j++){
            T.change(1,1,tot,vec[i][j].color,vec[i][j].num);
        //  cout<<i<<"::"<<vec[i][j].color<<" "<<vec[i][j].num<<endl;   
        }
        par tmp=T.querymax(1,1,tot,1,tot);
        if(tmp.first!=0)ans[rl[i]]=tmp.second;
        else ans[rl[i]]=0;
    }
}

int main(){
    int n,m,u,v,w;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }   
    dfs1(1,0);
    dfs2(1,0);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&u,&v,&w);
        if(ma[w]==0)ma[w]=++tot,ma2[tot]=w;     
        lca(u,v,ma[w]);
    }
    T.build(1,1,tot);   
    getans(n);
    for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值