【GDOI2014模拟】雨天的尾巴

来源:互联网 发布:金海岸大酒店网络地图 编辑:程序博客网 时间:2024/05/01 12:50

题目

深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连
根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。
首先村落里的一共有n 座房屋,并形成一个树状结构。然后救济粮分m 次发放,每次选择
两个房屋(x,y),然后对于x 到y 的路径上(含x 和y) 每座房子里发放一袋z 类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。

分析

相信大多数人都跟我一样,看到这道题,果断认为是树链剖分。
其实不然(我1.5h把熟练剖分打出来,以为能过50%。结果打错了,20%。然后。。。打暴力的人都是50%,#%……&*)。
我们注意到z<=10^9,那么**的数据范围。
但是m<=100000,所以就先做个离散化。
。。。
接着用到个很神奇的东西,叫线段树合并。
对于树上的每一个节点开一棵线段树,记录该节点的每个z的数量以及某一段z的最大值。注意要动态开节点,否则会爆空间。
发现,如果要修改从xy的路径,其实就是将x的z值加一,y的z值加一,lca(x,y)的z值减一以及fa[lca(x,y)]的z值减一(why?因为当线段树合并后从xlca(x,y)的路径上和从ylca(x,y)的路径上的每个节点的z值都加一,但lca(x,y)这个节点重复加了,那么就减掉。不过剩余的z值还会继续上传,所以在fa[lca(x,y)]就把上传的z值减去)
合并操作

int mesh(int x,int y,int l,int r){    if(l==r)    {        tree[x].v+=tree[y].v;        return 0;                                                        }    int mid=(l+r)/2;    if(tree[y].l)    {        if(!tree[x].l)            tree[x].l=tree[y].l;            else        mesh(tree[x].l,tree[y].l,l,mid);    }    if(tree[y].r)    {        if(!tree[x].r)            tree[x].r=tree[y].r;            else        mesh(tree[x].r,tree[y].r,mid+1,r);    }    tree[x].v=max(tree[tree[x].l].v,tree[tree[x].r].v);}

当然,当所有的修改操作做完后才线段树合并,否则会超时。


#include <cmath>#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <queue>const int maxlongint=2147483647;using namespace std;struct trees{    int l,r,v;}tree[8000000];struct read{    int x,y,z;}re[110000];int next[201000],last[201000],to[201000],po,tot,n,m,g[200000][20],t[200000],deep[200000],f[200000],sum,ans[2000000];bool cmp(read x,read y){    return x.z<y.z;}int bj(int x,int y){    next[++tot]=last[x];    last[x]=tot;    to[tot]=y;}int dg(int x){    for(int i=last[x];i;i=next[i])    {        int j=to[i];        if(j!=g[x][0])        {            deep[j]=deep[x]+1;            g[j][0]=x;            dg(j);        }    }}int prelca(){    for(int j=1;j<=log2(n);j++)    {        for(int i=1;i<=n;i++)        {            g[i][j]=g[g[i][j-1]][j-1];        }    }}int lca(int x,int y){    if(deep[x]>deep[y])    {        x=x^y;        y=x^y;        x=x^y;    }    for(int i=log2(n);i>=0;i--)    {        if(deep[g[y][i]]>deep[x])            y=g[y][i];    }    if(deep[y]!=deep[x]) y=g[y][0];    for(int i=log2(n);i>=0;i--)    {        if(g[y][i]!=g[x][i])        {            y=g[y][i];            x=g[x][i];        }    }    if(x!=y) y=g[y][0];    return y;}int put(int v,int l,int r,int x,int y){    if(l==r)    {        tree[v].v+=y;        return 0;    }    int mid=(l+r)/2;    if(x<=mid)    {        if(!tree[v].l)            tree[v].l=++sum;        put(tree[v].l,l,mid,x,y);    }    else    {        if(!tree[v].r)            tree[v].r=++sum;        put(tree[v].r,mid+1,r,x,y);     }    tree[v].v=max(tree[tree[v].l].v,tree[tree[v].r].v);}int work(int x,int y,int z){    int lc=lca(x,y);    if(!f[x])    {        f[x]=++sum;    }    put(f[x],1,tot,z,1);    if(!f[y])    {        f[y]=++sum;    }    put(f[y],1,tot,z,1);    if(!f[lc])    {        f[lc]=++sum;    }    put(f[lc],1,tot,z,-1);    if(g[lc][0])    {        if(!f[g[lc][0]]) f[g[lc][0]]=++sum;        put(f[g[lc][0]],1,tot,z,-1);    }}int mesh(int x,int y,int l,int r){    if(l==r)    {        tree[x].v+=tree[y].v;        return 0;                                                        }    int mid=(l+r)/2;    if(tree[y].l)    {        if(!tree[x].l)            tree[x].l=tree[y].l;            else        mesh(tree[x].l,tree[y].l,l,mid);    }    if(tree[y].r)    {        if(!tree[x].r)            tree[x].r=tree[y].r;            else        mesh(tree[x].r,tree[y].r,mid+1,r);    }    tree[x].v=max(tree[tree[x].l].v,tree[tree[x].r].v);}int find(int v,int l,int r){    if(l==r)    {        return l;    }    if(tree[tree[v].l].v==0 && tree[tree[v].r].v==0)        return 0;    int mid=(l+r)/2;    if(tree[tree[v].l].v>=tree[tree[v].r].v)    {        return find(tree[v].l,l,mid);    }    else    {        return find(tree[v].r,mid+1,r);     }}int merge(int x){    for(int i=last[x];i;i=next[i])    {        int j=to[i];        if(j!=g[x][0])        {            merge(j);            if(!f[x])            {                       f[x]=++sum;            }               if(!f[j])            {                       f[j]=++sum;            }            mesh(f[x],f[j],1,tot);        }    }    ans[x]=find(f[x],1,tot);}int main(){    scanf("%d",&n);    scanf("%d",&m);    for(int i=1;i<=n-1;i++)    {        int x,y;        scanf("%d%d",&x,&y);        bj(x,y);        bj(y,x);    }    deep[1]=1;    dg(1);    prelca();    for(int i=1;i<=m;i++)    {        scanf("%d%d%d",&re[i].x,&re[i].y,&re[i].z);    }    sort(re+1,re+m+1,cmp);    tot=0;    sum=0;    for(int i=1;i<=m;i++)    {        if(re[i].z==t[tot])        {            re[i].z=tot;        }        else        {            t[++tot]=re[i].z;            re[i].z=tot;        }    }    for(int i=1;i<=m;i++)    {        work(re[i].x,re[i].y,re[i].z);    }    merge(1);    for(int i=1;i<=n;i++)    {        if(!f[i])        {                   f[i]=++sum;        }           printf("%d\n",t[ans[i]]);    }}
1 0