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
- bnuoj 39566 Do use segment tree(树链剖分)
- BNUOJ 39566 Do use segment tree(树链剖分——点权)
- Aizu 2450 Do use segment tree (树链剖分)
- Aoj 2450 Do use segment tree【树链剖分】
- aoj2450 Do use segment tree 树链剖分
- Do use segment tree 树链剖分,按顺序剖分
- AOJ 2450 Do use segment tree (树链剖分 + 线段树区间合并)
- BNUOJ39566 Do use segment tree (树链剖分+维护区间最大连续和)
- Aizu 2450 Do use segment tree LCT
- 树链剖分 JAG Summer 2012 Day 4 D Do use segment tree
- 线段树(segment tree)
- 线段树(Segment Tree)
- 线段树(segment tree)
- 区间树(segment tree)
- Codeforces755D (segment tree,implementation)
- segment tree(线段树)
- Segment Tree(线段树)
- 线段树(segment tree)
- hdu 2243(ac自动机+矩阵快速幂)
- js返回上一页并刷新的多种实现方法
- java事务的处理
- 黑马程序员----Objective-C学习笔记之内存管理
- Centos 7 安装 vim自动补全神器 YouCompleteMe
- bnuoj 39566 Do use segment tree(树链剖分)
- iOS中的定时器
- 【计蒜客】难题题库 004 简单斐波那契
- Mac下如何安装调试apk
- ios 本地通知
- 起泡排序/快速排序
- 实现队列的MAX函数:返回队列中的最大值
- C++初始化变量
- PHP学习笔记(03)—— 控制结构