[JZOJ3397]雨天的尾巴

来源:互联网 发布:nginx 1.8 域名配置 编辑:程序博客网 时间:2024/04/25 17:22

题目大意

一棵n个节点的树,有m个修改操作,都为将从xy路径上所有点添加一个种类为z的信息。
询问所有操作完成之后,所有点个数最多的分别是哪一个种类的信息。

1n,m105,1z109


题目分析

将种类离散化,然后直接建权值线段树,在树上线段树合并即可。
每一个修改可以拆成对四个点的单点修改。
时间复杂度O((n+m)log2n)


代码实现

#include <algorithm>#include <iostream>#include <cstdio>#include <cctype>#include <cmath>using namespace std;int read(){    int x=0,f=1;    char ch=getchar();    while (!isdigit(ch)) ch=getchar();    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();    return x*f;}const int N=100500;const int M=100500;const int Q=M*4;const int E=N-1<<1;const int LGN=18;const int S=N*LGN;const int EL=N<<1;const int LGEL=19;int root[N];struct segment_tree{    int son[S][2],mx[S][2];    int tot;    int newnode()    {        return ++tot,son[tot][0]=son[tot][1]=mx[tot][0]=mx[tot][1]=0,tot;    }    void update(int rt,int l,int r)    {        if (mx[l=son[rt][0]][1]>mx[r=son[rt][1]][1]||mx[l][1]==mx[r][1]&&mx[l][0]<mx[r][0])            mx[rt][0]=mx[l][0],mx[rt][1]=mx[l][1];        else            mx[rt][0]=mx[r][0],mx[rt][1]=mx[r][1];    }    void modify(int &rt,int y,int l,int r,int delta)    {        if (!rt) rt=newnode();        if (l==r)        {            mx[rt][0]=y,mx[rt][1]+=delta;            return;        }        int mid=l+r>>1;        if (y<=mid) modify(son[rt][0],y,l,mid,delta);        else modify(son[rt][1],y,mid+1,r,delta);        update(rt,l,r);    }    void merge(int &rt1,int rt2,int l,int r)    {        if (!(rt1&&rt2))        {            rt1+=rt2;            return;        }        if (l==r)        {            mx[rt1][1]+=mx[rt2][1];            return;        }        int mid=l+r>>1;        merge(son[rt1][0],son[rt2][0],l,mid),merge(son[rt1][1],son[rt2][1],mid+1,r);        update(rt1,l,r);    }}t;struct data{    int id,key;    data (int id0=0,int key0=0){id=id0,key=key0;}}srt[M];bool operator<(data a,data b){return a.key<b.key;}int last[N],h[N],pos[N],top[N],fa[N],ans[N],typ[N];int change[Q][2]/*tp delta*/,nxt[Q];int n,m,tot,cnt,el,lgel,idx;int next[E],tov[E];int rmq[EL][LGEL];int euler[EL];int C[M][3];void insert(int x,int y){    tov[++tot]=y,next[tot]=last[x],last[x]=tot;}void require(int x,int tp,int delta){    change[++cnt][0]=tp,change[cnt][1]=delta;    nxt[cnt]=top[x],top[x]=cnt;}void dfs(int x){    h[x]=h[fa[x]]+1,euler[++el]=x,rmq[el][0]=x,pos[x]=el;    for (int i=last[x],y;i;i=next[i])        if (fa[x]!=(y=tov[i]))            fa[y]=x,dfs(y),euler[++el]=x,rmq[el][0]=x;}void pre(){    lgel=trunc(log(el)/log(2));    for (int j=1;j<=lgel;j++)        for (int i=1;i+(1<<j)-1<=el;i++)            rmq[i][j]=h[rmq[i][j-1]]<h[rmq[i+(1<<j-1)][j-1]]?rmq[i][j-1]:rmq[i+(1<<j-1)][j-1];}int getrmq(int l,int r){    int lgr=trunc(log(r-l+1)/log(2));    return h[rmq[l][lgr]]<h[rmq[r-(1<<lgr)+1][lgr]]?rmq[l][lgr]:rmq[r-(1<<lgr)+1][lgr];}int lca(int x,int y){    if ((x=pos[x])>(y=pos[y])) x^=y^=x^=y;    return getrmq(x,y);}void calc(int x){    int rt=0;    for (int i=last[x],y;i;i=next[i])        if (fa[x]!=(y=tov[i]))            calc(y),t.merge(rt,root[y],1,n);    for (int i=top[x];i;i=nxt[i])        t.modify(rt,change[i][0],1,n,change[i][1]);    ans[x]=t.mx[root[x]=rt][0];}int main(){    freopen("rain.in","r",stdin);    freopen("rain.out","w",stdout);    n=read(),m=read();    for (int i=1,u,v;i<n;i++)    {        u=read(),v=read();        insert(u,v),insert(v,u);    }    dfs(1),pre();    for (int i=1;i<=m;i++)        C[i][1]=read(),C[i][2]=read(),srt[i].key=C[i][0]=read(),srt[i].id=i;    sort(srt+1,srt+1+m);    for (int i=1;i<=m;i++) C[srt[i].id][0]=idx+=(srt[i].key!=srt[i-1].key),typ[idx]=srt[i].key;    for (int i=1,u,v,w;i<=m;i++)    {        u=C[i][1],v=C[i][2],w=C[i][0];        int x=lca(u,v);        require(u,w,1),require(v,w,1),require(x,w,-1);        if (fa[x]) require(fa[x],w,-1);    }    calc(1);    for (int i=1;i<=n;i++) printf("%d\n",typ[ans[i]]);    fclose(stdin);    fclose(stdout);    return 0;}
0 0
原创粉丝点击