hdu 5029 Relief grain (树链剖分+线段树)

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

题意:给出一棵树,和一种操作。 操作a,b,k相当于将树上a,b结点间的路径上的节点都加上一个k值,最后输出每个结点被加最多次的那个数。

思路:先用树链剖分将问题转化到线性结构上,然后来考虑如何在线性来解决这个问题。 相当于区间染色,最后问每个点被染次数最多的那个颜色。

做法:对于每个操作a,b,k,我们将a节点上标记一个k,b+1节点上标记一个-k,多个不标记我们可以用vector来存储,先将所有的操作都打到这个线性的结构上,再用线段树来维护.

区间a~b上维护的是从颜色a到颜色b出现最多的颜色的标号,这样的话我们可以从左向右来扫描打好标记的线性结构,扫到每个节点都将他所存储的标号更新到线段树上,如果标记

是正值就将对应的颜色的次数+1,否则-1,将所有的标记都传完后,取根节点的值(维护的是整个区间)就能够知道当前被染次数最多的值。 感觉方法十分的巧妙。

code:

#include 
#include 
#include 
#include 
#include 
#include 
#pragma comment(linker, "/STACK:102400000,102400000") 

using namespace std;

const int maxn=105000;
const int maxe=400010;

struct edge
{
    int to,next;
} P[maxe];

int head[maxn],si;
int fa[maxn],deep[maxn],son[maxn],num[maxn];
int top[maxn],p[maxn],fp[maxn],pos;

void init()
{
    si=0;
    memset(head,-1,sizeof(head));
    pos=1;
    memset(son,-1,sizeof(son));
}

void add_edge(int s,int t)
{
    P[si].to=t;
    P[si].next=head[s];
    head[s]=si++;
}

void dfs1(int u,int pre,int d)
{
    deep[u]=d;
    fa[u]=pre;
    num[u]=1;
    for(int i=head[u];i!=-1;i=P[i].next){
        int v=P[i].to;
        if(v!=pre){
            dfs1(v,u,d+1);
            num[u]+=num[v];
            if(son[u]==-1||num[v]>num[son[u]]) son[u]=v;
        }
    }
}
void getpos(int u,int sp)
{
    top[u]=sp;
    p[u]=pos++;
    fp[p[u]]=u;
    if(son[u]==-1) return ;
    getpos(son[u],sp);
    for(int i=head[u];i!=-1;i=P[i].next){
        int v=P[i].to;
        if(v!=son[u]&&v!=fa[u]) getpos(v,v);
    }

}
vector w[maxn];
void add(int u,int v,int tt)
{
    int f1=top[u],f2=top[v];
    while(f1!=f2){
        if(deep[f1]deep[v]) swap(u,v);
    w[p[u]].push_back(tt);
    w[p[v]+1].push_back(-tt);
}
//线段树部分
int n,cc[maxn];
struct ppp
{
    int l,r,dat;
} ss[4*maxn+10];

void Build(int k,int ll,int rr)
{
    ss[k].l=ll;
    ss[k].r=rr;
    if(ll==rr){
        ss[k].dat=ll;
        return ;
    }
    else    ss[k].dat=0;
    Build((k<<1)+1,ll,(ll+rr)/2);
    Build((k<<1)+2,(ll+rr)/2+1,rr);
}
void init_tree(int n_)
{
    n=1;
    while(n0){
        k=(k-1)/2;
        if(cc[ss[2*k+1].dat]>=cc[ss[2*k+2].dat])
            ss[k].dat=ss[2*k+1].dat;
        else
            ss[k].dat=ss[2*k+2].dat;
    }
}

int ans[maxn];
int main()
{
    int nn,mm,col;
    int s,t,tt;
    while(scanf("%d%d",&nn,&mm),nn!=0||mm!=0){
        init();
        col=0;
        memset(ans,0,sizeof(ans));
        memset(cc,0,sizeof(cc));
        for(int i=1;i0) update(w[i][j],1);
                else          update(-w[i][j],-1);
            }
            ans[fp[i]]=ss[0].dat;
        }
        for(int i=1;i<=nn;i++) printf("%d\n",ans[i]);
    }
    return 0;
}

还有一种方法就是用set,首先定义一个pair,其first值存的是颜色出现的次数,second值存的是对应的颜色,set对应的是先按fisrt排序,其次再按second的排序,就可以了。

你可能感兴趣的:(树链剖分,Hdu,Solutions,线段树)