【BZOJ3999】【TJOI2015】旅游 树剖

来源:互联网 发布:手机淘宝设置降价提醒 编辑:程序博客网 时间:2024/05/02 22:33

题目大意

  给你一棵树,有n个点。有q个操作,每次要你从xy的路径上选两个点,使得距离x比较远的点的点权距离x比较近的点的点权最大,然后把这条路径上所有点的点权+v

  n,q50000

题解

  这种题没什么意思,直接树剖就好了。

  线段树上每个点记录最大值,最小值,从左往右走和从右往左走的最大收益。

  时间复杂度:O(n+qlog2n)

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>#include<cmath>#include<functional>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;typedef pair<ll,ll> pll;void sort(int &a,int &b){    if(a>b)        swap(a,b);}void open(const char *s){#ifndef ONLINE_JUDGE    char str[100];    sprintf(str,"%s.in",s);    freopen(str,"r",stdin);    sprintf(str,"%s.out",s);    freopen(str,"w",stdout);#endif}int rd(){    int s=0,c;    while((c=getchar())<'0'||c>'9');    do    {        s=s*10+c-'0';    }    while((c=getchar())>='0'&&c<='9');    return s;}int upmin(int &a,int b){    if(b<a)    {        a=b;        return 1;    }    return 0;}int upmax(int &a,int b){    if(b>a)    {        a=b;        return 1;    }    return 0;}struct pp{    ll ma,mi;    ll s1,s2;    pp()    {        ma=mi=s1=s2=0;    }};pp merge(pp a,pp b){    pp c;    c.s1=max(b.ma-a.mi,max(a.s1,b.s1));    c.s2=max(a.ma-b.mi,max(a.s2,b.s2));    c.ma=max(a.ma,b.ma);    c.mi=min(a.mi,b.mi);    return c;}pp rev(pp a){    swap(a.s1,a.s2);    return a;}int c[100010];namespace seg{    struct tree    {        int ls,rs;        int l,r;        ll t;        pp s;    };    tree a[100010];    int cnt;    void build(int &p,int l,int r)    {        p=++cnt;        a[p].l=l;        a[p].r=r;        if(l==r)        {            a[p].s.ma=a[p].s.mi=c[l];            return;        }        int mid=(l+r)>>1;        build(a[p].ls,l,mid);        build(a[p].rs,mid+1,r);        a[p].s=merge(a[a[p].ls].s,a[a[p].rs].s);    }    void add(int p,ll v)    {        a[p].s.ma+=v;        a[p].s.mi+=v;        a[p].t+=v;    }    void push(int p)    {        if(a[p].t&&a[p].ls!=a[p].r)        {            add(a[p].ls,a[p].t);            add(a[p].rs,a[p].t);            a[p].t=0;        }    }    void add(int p,int l,int r,int v)    {        if(l<=a[p].l&&r>=a[p].r)        {            add(p,v);            return;        }        push(p);        int mid=(a[p].l+a[p].r)>>1;        if(l<=mid)            add(a[p].ls,l,r,v);        if(r>mid)            add(a[p].rs,l,r,v);        a[p].s=merge(a[a[p].ls].s,a[a[p].rs].s);    }    pp query(int p,int l,int r)    {        if(l<=a[p].l&&r>=a[p].r)            return a[p].s;        push(p);        int mid=(a[p].l+a[p].r)>>1;        if(r<=mid)            return query(a[p].ls,l,r);        if(l>mid)            return query(a[p].rs,l,r);        return merge(query(a[p].ls,l,r),query(a[p].rs,l,r));    }}struct graph{    int v[100010];    int t[100010];    int h[50010];    int n;    graph()    {        n=0;    }    void add(int x,int y)    {        n++;        v[n]=y;        t[n]=h[x];        h[x]=n;    }};graph g;struct p{    int f,w,t,d,ms,s;};p a[100010];int wcnt;void dfs1(int x,int fa,int dep){    a[x].f=fa;    a[x].d=dep;    a[x].s=1;    int ms=0;    int i;    for(i=g.h[x];i;i=g.t[i])        if(g.v[i]!=fa)        {            dfs1(g.v[i],x,dep+1);            if(a[g.v[i]].s>ms)            {                ms=a[g.v[i]].s;                a[x].ms=g.v[i];            }            a[x].s+=a[g.v[i]].s;        }}void dfs2(int x,int top){    a[x].w=++wcnt;    a[x].t=top;    if(!a[x].ms)        return;    dfs2(a[x].ms,top);    int i;    for(i=g.h[x];i;i=g.t[i])        if(g.v[i]!=a[x].f&&g.v[i]!=a[x].ms)            dfs2(g.v[i],g.v[i]);}int prize[100010];int rt;ll query(int x,int y,int z){    pp s1,s2;    s1.ma=s1.mi=0x7fffffff;    s2.ma=s2.mi=-0x7fffffff;    while(a[x].t!=a[y].t)        if(a[a[x].t].d>a[a[y].t].d)        {            s1=merge(s1,rev(seg::query(rt,a[a[x].t].w,a[x].w)));            seg::add(rt,a[a[x].t].w,a[x].w,z);            x=a[a[x].t].f;        }        else        {            s2=merge(seg::query(rt,a[a[y].t].w,a[y].w),s2);            seg::add(rt,a[a[y].t].w,a[y].w,z);            y=a[a[y].t].f;        }    if(a[x].w<a[y].w)    {        s2=merge(seg::query(rt,a[x].w,a[y].w),s2);        seg::add(rt,a[x].w,a[y].w,z);    }    else    {        s1=merge(s1,rev(seg::query(rt,a[y].w,a[x].w)));        seg::add(rt,a[y].w,a[x].w,z);    }    s1=merge(s1,s2);    return s1.s1;}int main(){    open("bzoj3999");    int n,q;    scanf("%d",&n);    int i,x,y,z;    for(i=1;i<=n;i++)        scanf("%d",&prize[i]);    for(i=1;i<n;i++)    {        scanf("%d%d",&x,&y);        g.add(x,y);        g.add(y,x);    }    dfs1(1,0,1);    dfs2(1,1);    for(i=1;i<=n;i++)        c[a[i].w]=prize[i];    seg::build(rt,1,n);    scanf("%d",&q);    for(i=1;i<=q;i++)    {        scanf("%d%d%d",&x,&y,&z);        ll ans=query(x,y,z);        printf("%lld\n",ans);    }    return 0;}
原创粉丝点击