bnuoj 39566 Do use segment tree(树链剖分)

来源:互联网 发布:淘宝详情页面设计 编辑:程序博客网 时间:2024/05/21 21:48

题目链接

给一棵树,有两种操作:

1 将a->b路径上的点权值改为c;

2 求a->b路径上的最大连续区间和。

思路:树链剖分。通过不断合并区间,维护区间最大左区间和、最大右区间和、区间最大连续和、区间和即可。

//#pragma comment(linker, "/STACK:10240000000,10240000000")#include<iostream>#include<stdio.h>#include<math.h>#include <string>#include<string.h>#include<map>#include<queue>#include<set>#include<utility>#include<vector>#include<algorithm>#include<stdlib.h>using namespace std;#define eps 1e-8#define pii pair<int,int>#define inf 0x3f3f3f3f#define rd(x) scanf("%d",&x)#define rd2(x,y) scanf("%d%d",&x,&y)#define ll long long int#define mod 1000000007//#define maxn 200005#define maxm 1000005const int maxn=200100;int ma(int a,int b){return a>b?a:b;}struct Ed{    int to,next;}edge[maxn*4];int head[maxn],pos;int top[maxn];int fa[maxn];int deep[maxn];int num[maxn];int p[maxn];int fp[maxn];int d,tot;int son[maxn];void addedge(int u,int v){    edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;}/*dfs和build_tree函数为将树映射到线段树上的初始化函数*/void dfs(int u) {    deep[u] = d;    num[u] = 1;    son[u] = 0;    d++;    for (int i = head[u]; ~i; i = edge[i].next) {        if (edge[i].to != fa[u]) {            fa[edge[i].to] = u;            dfs(edge[i].to);            num[u] += num[edge[i].to];            if (son[u] == 0 || num[edge[i].to] > num[son[u]]) son[u] = edge[i].to;        }    }    d--;}void build_tree(int u, int tp) {    p[u] = pos++;  top[u] = tp;    if (son[u] > 0) build_tree(son[u], tp);    for (int i = head[u]; ~i; i = edge[i].next) {        if (edge[i].to != fa[u] && edge[i].to != son[u])            build_tree(edge[i].to, edge[i].to);    }}void init(){    tot=0;pos=0;    memset(head,-1,sizeof(head));    memset(son,-1,sizeof(son));}struct node{    int l,r,ml,mr,ms,k,v,s;//k为覆盖标记}tree[maxn*4];int a[maxn],b[maxn];node max_node(node ls,node rs){//求两个区间合并后的信息,    node ans;                  //最大左连续值,最大右连续值和区间最大连续值h和区间和    ans.k=0;    ans.l=ls.l;ans.r=rs.r;    ans.ml=ma(ls.ml,ls.s+rs.ml);    ans.mr=ma(rs.mr,rs.s+ls.mr);    ans.s=ls.s+rs.s;    ans.ms=ma(ls.ms,ma(rs.ms,ls.mr+rs.ml));    return ans;}void build(int i,int l,int r){    tree[i].l=l;tree[i].r=r;    tree[i].k=0;    if(l==r) {          tree[i].s=tree[i].ml=tree[i].mr=tree[i].ms=b[l];            return;    }    int mid=(l+r)>>1;    build(i<<1,l,mid);    build((i<<1)|1,mid+1,r);    tree[i]=max_node(tree[i*2],tree[i*2+1]);}void push_down(int i){    int ls=i*2;    int rs=i*2+1;    if(tree[i].k){        tree[ls].k=tree[rs].k=1;        tree[ls].v=tree[rs].v=tree[i].v;        tree[ls].s=(tree[ls].r-tree[ls].l+1)*tree[i].v;        tree[rs].s=(tree[rs].r-tree[rs].l+1)*tree[i].v;        if(tree[i].v>=0){            tree[ls].ml=tree[ls].mr=tree[ls].ms=tree[ls].s;            tree[rs].ml=tree[rs].mr=tree[rs].ms=tree[rs].s;        }        else{            tree[ls].ml=tree[ls].mr=tree[ls].ms=tree[i].v;            tree[rs].ml=tree[rs].mr=tree[rs].ms=tree[i].v;        }    }    tree[i].k=0;}void update(int i,int l,int r,int val){    if(tree[i].l==l&&tree[i].r==r){      tree[i].k=1;      tree[i].v=val;      tree[i].s=val*(r-l+1);      if(val>0) {        tree[i].ml=tree[i].mr=tree[i].ms=tree[i].s;      }      else{            tree[i].ml=tree[i].mr=tree[i].ms=val;      }        return;    }    push_down(i);    int mid=(tree[i].l+tree[i].r)>>1;    if(mid>=r) update(i<<1,l,r,val);    else if(l>mid) update((i<<1)|1,l,r,val);    else{        update(i<<1,l,mid,val);        update((i<<1)|1,mid+1,r,val);    }    tree[i]=max_node(tree[i*2],tree[i*2+1]);}void change(int u,int v,int val){    int f1=top[u],f2=top[v];    while(f1!=f2){        if(deep[f1]<deep[f2]){            swap(u,v);          swap(f1,f2);        }        update(1,p[f1],p[u],val);        u=fa[f1];f1=top[u];    }    if(deep[u]>deep[v]) {            swap(u,v);    }    update(1,p[u],p[v],val);}node query(int i,int l,int r){    if(tree[i].l==l&&tree[i].r==r){        return tree[i];    }    push_down(i);    int mid=(tree[i].l+tree[i].r)>>1;     if(mid>=r) return query(i<<1,l,r);    else if(l>mid) return query((i<<1)|1,l,r);    else{        node ls=query(i<<1,l,mid);        node rs=query((i<<1)|1,mid+1,r);        return max_node(ls,rs);    }}int query(int u,int v){//求路径上的最大连续区间,不断合并被剖分成的区间维护信息集合,注意合并方向    int f1=top[u],f2=top[v];   int k1=0,k2=0;   node ans1,ans2;    while(f1!=f2){       /* if(deep[f1]<deep[f2]){            swap(f1,f2);            swap(u,v);        }        update(1,p[f1],p[u],val);        u=fa[f1];f1=top[u];*/       if(deep[f1]>=deep[f2]){        node aa=query(1,p[f1],p[u]);        u=fa[f1];f1=top[u];        if(k1) ans1=max_node(aa,ans1);        else { k1=1; ans1=aa;        }       }       else{        node aa=query(1,p[f2],p[v]);        v=fa[f2];f2=top[v];        if(k2) ans2=max_node(aa,ans2);        else { k2=1; ans2=aa;        }       }    }   // if(deep[u]>deep[v]) swap(u,v);   // update(1,p[u],p[v],val);   if(deep[u]<=deep[v]){    node aa=query(1,p[u],p[v]);    if(k2) ans2=max_node(aa,ans2);        else { k2=1; ans2=aa;        }   }   else{    node aa=query(1,p[v],p[u]);    if(k1) ans1=max_node(aa,ans1);        else { k1=1; ans1=aa;        }   }   if(k1&&k2){    swap(ans1.ml,ans1.mr);    node aa=max_node(ans1,ans2);    return aa.ms;   }   else if(k1) return ans1.ms;   else return ans2.ms;}int n,q,u,v,z,op;int main(){   // rd(t);    while(~rd2(n,q)){        //rd(n);        init();        for(int i=1;i<=n;i++){            rd(a[i]);        }        for(int i=1;i<n;i++){            rd2(u,v);            addedge(u,v);            addedge(v,u);        }       // dfs1(1,0,0);       // getpos(1,1);       d=1;       dfs(1);       build_tree(1,1);        for(int i=1;i<=n;i++){            b[p[i]]=a[i];        }        build(1,0,n-1);        for(int i=1;i<=q;i++){            rd2(op,u);rd2(v,z);            if(op==1) change(u,v,z);            else{                printf("%d\n",query(u,v));            }        }    }    return 0;}


0 0