hdu-5029

这是一道树链剖分的题目

做法:1.对树进行剖分,在更新的区间段上的左端点,打(谷物种类,1)标记,表示谷物加入该区间段的节点,在右端点加1的位置,打(谷物种类,-1)标记,表示减去前面加上的谷物,消去对后面区间段的影响。

2.以谷物种类为下标,维护区间段内,谷物数量的最大值,还有,当前最大值的谷物种类。从左向右加入标记,即可求出答案。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
#include<iostream>
using namespace std;
#define clr(a,b) memset(a,b,sizeof(a))
const int INF=~(1<<(sizeof(int )*8-1));
typedef long long ll;
typedef pair<int,int > P;
#define MOD 1000000007
#define MAXN 100010
int n,m,q,tot;
int siz[MAXN],depth[MAXN],son[MAXN],par[MAXN],top[MAXN],id[MAXN],rak[MAXN];
int ans[MAXN];
vector<int> G[MAXN];
vector<P> sav[MAXN];
struct node{
    int l,r;
    int num;
    int maxn;
    int mid()
    {
        return (l+r)/2;
    }
}tree[4*MAXN];


void build(int l,int r,int i)
{
    tree[i].l=l;
    tree[i].r=r;
    tree[i].maxn=0;
    tree[i].num=-1;
    if(l==r) return;
    int mid=tree[i].mid();
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
}

void update(int x,int val,int i)
{
    if(tree[i].l==tree[i].r)
    {
        tree[i].num=x;
        tree[i].maxn+=val;
        return ;
    }
    int mid=tree[i].mid();
    if(x<=mid) update(x,val,i<<1);
    else update(x,val,i<<1|1);
    if(tree[i<<1].maxn>=tree[i<<1|1].maxn)
        tree[i].num=tree[i<<1].num;
    else tree[i].num=tree[i<<1|1].num;
    tree[i].maxn=max(tree[i<<1].maxn,tree[i<<1|1].maxn);
}

void init()
{
    tot=0;
    son[0]=0;
    for(int i=1;i<=n;i++)
    {
        son[i]=-1;
        G[i].clear();
        sav[i].clear();
    }
    build(1,100000,1);
}

void dfs1(int u,int pre,int deep)
{
    depth[u]=deep;
    siz[u]=1;
    par[u]=pre;
    int tp=0;
    for(int i=0,sz=G[u].size();i<sz;i++)
    {
        int v=G[u][i];
        if(v!=pre)
        {
            dfs1(v,u,deep+1);
            siz[u]+=siz[v];
            if(siz[tp]<siz[v])
                tp=v;
        }
    }
    if(tp) son[u]=tp;
}

void dfs2(int u,int high)
{
    top[u]=high;
    id[u]=++tot;
    rak[tot]=u;
    if(son[u]!=-1)
        dfs2(son[u],high);
    for(int i=0,sz=G[u].size();i<sz;i++)
    {
        int v=G[u][i];
        if(v!=par[u]&&v!=son[u])
            dfs2(v,v);
    }
}

void change(int x,int y,int val)
{
    while(top[x]!=top[y])
    {
        if(depth[top[x]]<depth[top[y]]) swap(x,y);
        sav[id[top[x]]].push_back(make_pair(val,1));
        sav[id[x]+1].push_back(make_pair(val,-1));
        x=par[top[x]];
    }
    if(depth[x]>depth[y]) swap(x,y);
    sav[id[x]].push_back(make_pair(val,1));
    sav[id[y]+1].push_back(make_pair(val,-1));
}


int main()
{
    //freopen("in","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0) break;
        init();
        for(int i=1;i<n;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
            G[b].push_back(a);
        }
        dfs1(1,-1,1);
        dfs2(1,1);
        for(int i=1;i<=m;i++)
        {
            int x,y,val;
            scanf("%d%d%d",&x,&y,&val);
            change(x,y,val);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=0,sz=sav[i].size();j<sz;j++)
            {
                P tp=sav[i][j];
                update(tp.first,tp.second,1);
                //printf("%d %d %d\n",rak[i],tp.first,tp.second);
            }
            //printf("maxn:%d num:%d\n",tree[1].maxn,tree[1].num);
            if(tree[1].maxn)
                ans[rak[i]]=tree[1].num;
            else ans[rak[i]]=0;
        }
        for(int i=1;i<=n;i++)
            printf("%d\n",ans[i]);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值