2014网络赛 hdu 5029 树链剖分 + 线段树

来源:互联网 发布:大卫杜夫冷水 知乎 编辑:程序博客网 时间:2024/06/06 14:19

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5029


题意:RT

先搞定一维的情况。

一维的问题就是给m个操作,每个操作给一个L,R,C,表示区间[L,R]增加一种颜色C。问最后每个点最多的颜色是什么。对于每个L,R C我们可以在L这个时刻在C这个点加一,在R+1这个点减一。这样将所有区间分成两个点L,R+1 将所有点按左到右排序。然后从左到右处理每个点。当处理到当前点i的时候。将区间那些点用线段树更新完,查询一下哪种最多就是了。

一维的解决完,二维的用树链剖分搞定将树链划分成logn个连续区间。然后对于划分后的区间就是一维的问题了。然后还原一下就ok。注意这里是点的修改,不是线段修改。

代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <iostream>#include <queue>#include <algorithm>#define lson L,mid,lc#define rson mid + 1,R,rc#define root 1,n,1using namespace std;const int N = 2000005;int eh[N],cnt,num,ans[N],re[N];struct Edge{    int from,to,next;    Edge(){}    Edge(int u,int v,int n):from(u),to(v),next(n){}}edge[N];struct cc{    int  v,id,val;    bool operator <(const cc &s)const{        return id < s.id;    }}ar[N];inline void add(int u,int v,int n){    edge[cnt] = Edge(u,v,n);}void addedge(int u,int v){    add(u,v,eh[u]);    eh[u] = cnt++;    add(v,u,eh[v]);    eh[v] = cnt++;}int fa[N],son[N],w[N],siz[N],dep[N],tot,top[N];void dfs1(int u,int d){    dep[u] = d;    int maxn = 0,id = 0,sum = 1;    for(int i = eh[u];i != -1;i = edge[i].next)    {        int v = edge[i].to;        if(v == fa[u])continue;        fa[v] = u;        dfs1(v,d + 1);        sum += siz[v];        if(siz[v] > maxn){maxn = siz[v],id = v;}    }    son[u] = id;siz[u] = sum;}void dfs2(int u){    re[++tot] = u;    w[u] = tot;    if(!top[u]) top[u] = u;    if(son[u])    {        top[son[u]] = top[u];        dfs2(son[u]);    }    for(int i = eh[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        if(v == fa[u] || v == son[u]) continue;        dfs2(v);    }}void init(){    memset(eh,-1,sizeof(eh));    memset(top,0,sizeof(top));    memset(son,0,sizeof(son));    memset(siz,0,sizeof(siz));    tot = cnt = num = 0;}void div(int L,int R,int z){    ++R;    ar[num].v = ar[num + 1].v = z;    ar[num].id = L;ar[num + 1].id = R;    ar[num++].val = 1;ar[num++].val = -1;}void find(int x,int y,int z){    int f1 = top[x],f2 = top[y];    while(f1 != f2)    {        if (dep[f1] < dep[f2]){swap(f1, f2); swap(x, y);}        div(w[f1],w[x],z);        x = fa[f1]; f1 = top[x];    }    if (dep[x] > dep[y]) swap(x, y);    div(w[x], w[y],z);}int c[N],maxn[N];void maintain(int lc,int rc,int o){    if(c[lc] == c[rc]){        if(maxn[lc] < maxn[rc]) { c[o] = c[lc];maxn[o] = maxn[lc];}        else {c[o] = c[rc];maxn[o] = maxn[rc];}    }else if(c[lc] > c[rc]){        c[o] = c[lc];maxn[o] = maxn[lc];    }else{        c[o] = c[rc];maxn[o] = maxn[rc];    }    if(c[o] == 0) maxn[o] = 0;}void update(int L,int R,int o,int p,int v){    if(L == R){        c[o] += v;        if(c[o])  maxn[o] = L;        else maxn[o] = 0;        return;    }    int mid = (L + R) >> 1;    int lc = o << 1,rc = lc | 1;    if(p <= mid) update(lson,p,v);    else update(rson,p,v);    maintain(lc,rc,o);}void solve(int kk,int m){   int n = 100002;    memset(maxn,0,sizeof(maxn));    memset(c,0,sizeof(c));    sort(ar,ar + num);    for(int i = 1,index = 0;i <= kk; ++i)    {        while(index < num && ar[index].id == i)        {            update(root,ar[index].v,ar[index].val);            ++index;        }        ans[re[i]] = maxn[1];    }    for(int i = 1; i <= kk; ++i)    {        printf("%d\n",ans[i]);    }}int main(){    int n,m;    while(~scanf("%d%d",&n,&m))    {        if(n == 0 && m == 0) return 0;        init();        for(int i = 1;i < n; ++i)        {            int u,v;            scanf("%d%d",&u,&v);            addedge(u,v);        }        dfs1(1,0);        dfs2(1);        for(int i = 0;i < m; ++i)        {            int x,y,z;            scanf("%d%d%d",&x,&y,&z);            find(x,y,z);        }        solve(n,m);    }    return 0;}


0 0