Aizu 2450 Do use segment tree (树链剖分)

来源:互联网 发布:杨子天珠淘宝店 编辑:程序博客网 时间:2024/05/22 04:36

Aizu 2450 Do use segment tree


树链剖分 + 线段树区间更新,就是用线段树求区间最大连续子序列和。

求区间最大连续子序列和  的  区间更新   都很好实现。

要注意的是最后询问的时候多个区间合并的顺序和正反的问题(就是后面swap那儿)

一开始线段树初始化那儿写残了调了好久  -  -


--------

孙大大的板子好长啊 -   -


#include <bits/stdc++.h>#define lson num<<1#define rson num<<1|1#define gl l,m,lson#define gr m+1,r,rson#define PARA int l=L,int r=R,int num=1using namespace std;const int MAXN = 2e5+100;const int INF = 0x2f2f2f2f;struct Node{    long long lmx,rmx,mx,sum,tag;    long long l,r;    void init(int a,int b)    {        l=a,r=b;        tag=INF;    }    void mark(long long v)    {        tag=v;        sum=v*(r-l+1);        mx=lmx=rmx=max(v,sum);    }    void merge(Node a, Node b)    {        lmx=max(max(a.lmx,a.sum),max(a.sum+b.lmx,a.sum+b.sum));        rmx=max(max(b.rmx,b.sum),max(b.sum+a.rmx,a.sum+b.sum));        sum=a.sum+b.sum;        mx=max(max(max(lmx,rmx),max(a.mx,b.mx)),a.rmx+b.lmx);    }    void swap()    {        ::swap(lmx,rmx);    }};int L,R;struct SegTree{    int num[MAXN];    Node st[MAXN<<2];    void pushUp(int num)    {        st[num].merge(st[lson],st[rson]);    }    void pushDown(int num)    {        long long &v=st[num].tag;        int l=st[num].l,r=st[num].r;        if(l!=r&&v!=INF)        {            st[lson].mark(v);            st[rson].mark(v);            pushUp(num);        }        v=INF;    }    void init(int v[],PARA)    {        int m=l+r>>1;        st[num].init(l,r);        if(l!=r)            init(v,gl),init(v,gr),pushUp(num);        else            st[num].mark(v[l]);    }    void update(int a,int b,int v,PARA)    {        pushDown(num);        if(a<=l&&r<=b)            st[num].mark(v);        else        {            int m=l+r>>1;            if(b<=m)                update(a,b,v,gl);            else if(a>m)                update(a,b,v,gr);            else                update(a,b,v,gl),update(a,b,v,gr);            pushUp(num);        }    }    Node query(int a,int b,PARA)    {        pushDown(num);        Node ret;        if(a<=l&&r<=b)            return st[num];        int m=l+r>>1;        if(b<=m)            ret=query(a,b,gl);        else if(a>m)            ret=query(a,b,gr);        else            ret.merge(query(a,b,gl),query(a,b,gr));        pushUp(num);        return ret;    }} tr;const int maxn=MAXN;const int maxm=maxn+maxn;struct EDGENODE{    int to;    int next;} edges[maxm];int head[maxn],edge;inline void init(){    edge=0;    memset(head,-1,sizeof(head));}inline void addedge(int u,int v){    edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;    edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++;}int que[maxn]; // 队列bool vis[maxn]; // 访问标记int son[maxn]; // 重儿子int idx[maxn]; // 结点v在其路径中的编号int dep[maxn]; // 结点v的深度int siz[maxn]; // 以结点v为根的子树的结点个数int belong[maxn]; // 结点v所属的路径编号int fa[maxn]; // 结点v的父亲结点int top[maxn]; // 编号为p的路径的顶端结点int len[maxn]; // 路径p的长度int sump[maxn]; // 路径p的编号int seg[maxn]; // 结点v的父边在线段树中的位置int wei[maxn]; // 结点v的父边的权值int l,r,ans,cnt;int n;char cmd[22];void split(){    memset(dep,-1,sizeof(dep));    l=0;    dep[ que[r=1]=1 ]=0; // 将根结点插入队列,并设深度为0    fa[1]=-1; // 默认 1 为根结点    while (l<r)  // 第一遍搜索求出 fa,dep,wei    {        int u=que[++l];        vis[u]=false; // 顺便初始化vis        for (int i=head[u]; i!=-1; i=edges[i].next)        {            int v=edges[i].to;            if (dep[v]==-1)  // 未访问过的结点            {                dep[ que[++r]=v ]=dep[u]+1; // 将v插入队列并设深度为dep[u]+1                fa[v]=u; // v的父结点为u            }        }    }    cnt=0; // 重链编号    for (int i=n; i>0; i--)    {        int u=que[i],p=-1;        siz[u]=1;        son[u]=p;        for (int k=head[u]; k!=-1; k=edges[k].next)        {            int v=edges[k].to;            if (vis[v])  // 若v是u的子结点            {                siz[u]+=siz[v]; // 计数                if (p==-1||siz[v]>siz[p])                {                    son[u]=v;                    p=v; // u的重儿子是v                }            }        }        if (p==-1)  // u是叶子结点        {            idx[u]=len[++cnt]=1; // 一个新的路径编号为cnt,u是路径中的第一个结点            belong[ top[cnt]=u ]=cnt; // u是顶端结点,且u属于路径cnt        }        else  // u不是叶子结点        {            idx[u]=++len[ belong[u]=belong[p] ]; // u属于重儿子所在的链,链长+1,u是路径中第len个结点            top[ belong[u] ]=u; // u是顶端结点        }        vis[u]=true; // 访问标记    }    sump[0]=0;    for (int i=1;i<=cnt;i++) sump[i]=sump[i-1]+len[i];    for (int i=1;i<=n;i++){        seg[i]=sump[ belong[i] ]-idx[i]+1;        tr.num[ seg[i] ]=wei[i];    }}int in[MAXN];void build(){    int a,b;    for(int i=1;i<=n;i++)        scanf("%d",&wei[i]);    for(int i=1;i<n;i++)        scanf("%d%d",&a,&b),addedge(a,b);    split();    for(int i=1;i<=n;i++)        in[seg[i]]=wei[i];    L=1,R=n;    tr.init(in);}Node q1[MAXN],q2[MAXN];long long find(int va,int vb){    int f1=top[belong[va]],f2=top[belong[vb]];    int s1=0,s2=0;    while (f1!=f2)    {        if (dep[f1]<dep[f2])        {            q2[s2++]=tr.query(seg[f2],seg[vb]);            vb=fa[f2];            f2=top[belong[vb]];        }        else        {            q1[s1]=tr.query(seg[f1],seg[va]);            q1[s1++].swap();            va=fa[f1];            f1=top[belong[va]];        }    }    for(int i=1;i<s1;i++)        q1[0].merge(q1[0],q1[i]);    for(int i=1;i<s2;i++)        q2[0].merge(q2[i],q2[0]);    int d=0;    if (dep[va]>dep[vb]) swap(va,vb),d=1;    Node ret=tr.query(seg[va],seg[vb]);    if(d)        ret.swap();    if(s1)        ret.merge(q1[0],ret);    if(s2)        ret.merge(ret,q2[0]);    return ret.mx;}void update(int va,int vb,int v){    int f1=top[belong[va]],f2=top[belong[vb]],tmp=-INF;    while (f1!=f2){        if (dep[f1]<dep[f2]){            swap(f1,f2);            swap(va,vb);        }        tr.update(seg[f1],seg[va],v);        va=fa[f1];        f1=top[belong[va]];    }    if (dep[va]>dep[vb]) swap(va,vb);    tr.update(seg[va],seg[vb],v);}int main(){    int q,a,b,c,d;    while(scanf("%d%d",&n,&q)!=EOF)    {        init();        build();        for(int i=0;i<q;i++)        {            scanf("%d%d%d%d",&a,&b,&c,&d);            if(a==1)                update(b,c,d);            else                printf("%lld\n",find(b,c));        }    }    return 0;}


0 0
原创粉丝点击