小白逛公园加强版(park)
小白逛公园加强版(park)
题目描述
小新经常陪小白去公园玩,也就是所谓的遛狗啦……在小新家附近有n个公园,这些公园通过一些路径相连,并保证每两个公园之间有且仅有一条通路相连(也就是说这是一棵树),小白早就看花了眼,自己也不清楚该去哪些公园玩了。
小白对每个公园都有一个评价(可正可负),并且它只会让小新做两件事:
1. 询问公园a到公园b路径上最大连续公园的评价和,就是说我们把公园a到公园b路径上的公园(包括a和b)排成一条直线,那么小白希望知道一段连续的公园的评价和最大为多少。
2. 修改公园a到公园b路径上(包括a和b)每个公园的评价值。
小新现在已经处理不了n超过10的情况,因此请你来帮忙……
输入
第一行有一个自然数,表示n
第二行有n个自然数,表示一开始小白对每个公园的评价(评价值的绝对值不超过10000)
下面有n-1行,每行两个数a和b,表示公园a和公园b直接由道路相连
再下面一行有一个自然数,表示m
最后m行,每行第一个数k表示要执行的操作。如果k为1,那么后面有两个自然数a和b,表示询问公园a到公园b路径上(包含a和b)最大的连续公园评价和(如果这条路径上每个公园的评价都为负数,那么最大连续和为0)。如果k为2,那么后面有三个自然数a、b和c,表示把公园a到公园b路径上所有的公园(包括a和b)的评价都修改为c。(c的绝对值不超过10000)
输出
对于每次询问,输出最大连续和。(每行一个)
样例输入
5
-3 -2 1 2 3
1 2
2 3
1 4
4 5
3
1 2 5
2 3 4 2
1 2 5
样例输出
5
9
提示
对于30%的数据:n,m <= 100
对于70%的数据:n,m <= 50000
对于100%的数据:n,m <= 100000
solution
先写个树剖,转化为区间问题。
考虑如何求一段区间权值和最大的连续子序列
在线段树中记
lm:从左开始的最大值
rm:从右开始的最大值
x:中间的最大值(包括两边)
sum:和
这样就可以维护了
void wh(int k){
tree[k].lm=max(tree[k*2].lm,tree[k*2].sum+tree[k*2+1].lm);
tree[k].rm=max(tree[k*2+1].rm,tree[k*2+1].sum+tree[k*2].rm);
tree[k].sum=tree[k*2].sum+tree[k*2+1].sum;
tree[k].x=max(max(tree[k*2].x,tree[k*2+1].x),tree[k*2].rm+tree[k*2+1].lm);
}
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100005
#define inf 1e9
using namespace std;
int n,m,head[maxn],son[maxn],fa[maxn],size[maxn],top[maxn],deep[maxn];
int dfn[maxn],dy[maxn],sc,t1,t2,tot,w[maxn],op,a,b,c,li,ri,ans;
struct node{
int lm,rm,x,sum,l,r;
int bj;
}tree[maxn*4],ansa,ansb;
struct no{
int v,nex;
}e[maxn*2];
void lj(int t1,int t2){
tot++;e[tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs1(int k,int fath){
fa[k]=fath;deep[k]=deep[fath]+1;
int gp=-1,sz=0;
for(int i=head[k];i;i=e[i].nex){
if(e[i].v!=fath){
dfs1(e[i].v,k);
sz+=size[e[i].v];
if(gp==-1)gp=e[i].v;
if(size[e[i].v]>size[gp])gp=e[i].v;
}
}
size[k]=sz+1;son[k]=gp;
}
void dfs2(int k){
dfn[k]=++sc;dy[sc]=k;
if(son[k]!=-1)top[son[k]]=top[k],dfs2(son[k]);
for(int i=head[k];i;i=e[i].nex){
if(e[i].v!=fa[k]&&e[i].v!=son[k]){
top[e[i].v]=e[i].v;
dfs2(e[i].v);
}
}
}
void wh(int k){
tree[k].lm=max(tree[k*2].lm,tree[k*2].sum+tree[k*2+1].lm);
tree[k].rm=max(tree[k*2+1].rm,tree[k*2+1].sum+tree[k*2].rm);
tree[k].sum=tree[k*2].sum+tree[k*2+1].sum;
tree[k].x=max(max(tree[k*2].x,tree[k*2+1].x),tree[k*2].rm+tree[k*2+1].lm);
}
void update(int k,int v){
tree[k].sum=(tree[k].r-tree[k].l+1)*v;
if(tree[k].sum<0)tree[k].x=tree[k].lm=tree[k].rm=0;
else tree[k].x=tree[k].lm=tree[k].rm=tree[k].sum;
}
void build(int k,int L,int R){
tree[k].l=L,tree[k].r=R;tree[k].bj=-inf;
if(L==R){
update(k,w[dy[L]]);
return;
}
int mid=L+R>>1;
build(k*2,L,mid);build(k*2+1,mid+1,R);
wh(k);
}
node hb(node a,node b){
node t;
t.lm=max(a.lm,a.sum+b.lm);
t.rm=max(b.rm,b.sum+a.rm);
t.sum=a.sum+b.sum;
t.x=max(max(a.x,b.x),a.rm+b.lm);
return t;
}
void down(int k){
if(tree[k].bj!=-inf){
tree[k*2].bj=tree[k*2+1].bj=tree[k].bj;
update(k*2,tree[k].bj);
update(k*2+1,tree[k].bj);
tree[k].bj=-inf;
}
}
node ask(int k){
if(tree[k].l>=li&&tree[k].r<=ri){
return tree[k];
}
down(k);
int mid=tree[k].l+tree[k].r>>1;
node now;now.x=-1e9;now.lm=now.rm=now.sum=0;
if(li<=mid)now=ask(k*2);
if(ri>mid)now=hb(now,ask(k*2+1));
return now;
}
void lian(int k){
if(tree[k].l>=li&&tree[k].r<=ri){
update(k,c);tree[k].bj=c;
return;
}
down(k);
int mid=tree[k].l+tree[k].r>>1;
if(li<=mid)lian(k*2);
if(ri>mid)lian(k*2+1);
wh(k);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&w[i]);
for(int i=1;i<n;i++){
scanf("%d%d",&t1,&t2);
lj(t1,t2);lj(t2,t1);
}
dfs1(1,0);top[1]=1;dfs2(1);
build(1,1,n);
cin>>m;
while(m--){
scanf("%d",&op);
if(op==1){
scanf("%d%d",&a,&b);
t1=top[a],t2=top[b];
ansa.x=-1e9;ansa.lm=ansa.rm=ansa.sum=0;
ansb.x=-1e9;ansb.lm=ansb.rm=ansb.sum=0;
while(t1!=t2){
if(deep[t1]>=deep[t2]){
li=dfn[t1],ri=dfn[a];
ansa=hb(ask(1),ansa);
a=fa[t1];t1=top[a];
}
else {
li=dfn[t2],ri=dfn[b];
ansb=hb(ask(1),ansb);
b=fa[t2];t2=top[b];
}
}
if(deep[a]<deep[b]){
li=dfn[a],ri=dfn[b];
ansb=hb(ask(1),ansb);
}
else {
li=dfn[b],ri=dfn[a];
ansa=hb(ask(1),ansa);
}
ans=max(ansa.x,ansb.x);
ans=max(ans,ansa.lm+ansb.lm);
printf("%d\n",max(ans,0));
}
else{
scanf("%d%d%d",&a,&b,&c);
t1=top[a],t2=top[b];
while(t1!=t2){
if(deep[t1]<deep[t2])swap(t1,t2),swap(a,b);
li=dfn[t1],ri=dfn[a];
lian(1);
a=fa[t1],t1=top[a];
}
if(deep[a]<deep[b])swap(a,b);
li=dfn[b],ri=dfn[a];
lian(1);
}
}
return 0;
}
小白逛公园加强版(park)的更多相关文章
- [vijos P1083] 小白逛公园
不知怎地竟有种错觉此题最近做过= =目测是类似的?那道题貌似是纯动归? 本来今晚想做两道题的,一道是本题,一道是P1653疯狂的方格取数或NOI08 Employee,看看现在的时间目测这个目标又达不 ...
- Bzoj 1756: Vijos1083 小白逛公园 线段树
1756: Vijos1083 小白逛公园 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1021 Solved: 326[Submit][Statu ...
- BZOJ 1756: Vijos1083 小白逛公园
题目 1756: Vijos1083 小白逛公园 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 856 Solved: 264[Submit][Sta ...
- JDOJ-P1260 VIJOS-P1083 小白逛公园
首先,在这里给大家推荐一个网站,https://neooj.com:8082,这是我母校的网站 言归正传,题目描述 VIJOS-P1083 小白逛公园 Time Limit: 1 Sec Memor ...
- 线段树 || BZOJ1756: Vijos1083 小白逛公园 || P4513 小白逛公园
题面:小白逛公园 题解: 对于线段树的每个节点除了普通线段树该维护的东西以外,额外维护lsum(与左端点相连的最大连续区间和).rsum(同理)和sum……就行了 代码: #include<cs ...
- 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间合并(单点更新、区间查询)
P4513 小白逛公园 题目背景 小新经常陪小白去公园玩,也就是所谓的遛狗啦… 题目描述 在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩 ...
- vijos1083:小白逛公园
小白逛公园 描述 小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了. 一开始,小白就根据公园的 ...
- TYVJ1427 小白逛公园
时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个 ...
- bzoj1756 Vijos1083 小白逛公园
Description 小新经常陪小白去公园玩,也就是所谓的遛狗啦-在小新家附近有一条"公园路",路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了. ...
随机推荐
- git系列讲解
1.git是什么呢?维基百科给出的定义: git是一个分布式版本控制软件,最初由(Linus Torvalds)创作 什么是版本控制?项目经理与程序员的恩怨情仇企业真实案例:开发了a功能,之后项目所要 ...
- 深入浅出:了解for循环中保留i值得方法
一.保留i值 通常情况下,因为一些效果我们需要获取到for循环中的i的值,但是往往拿到的都是最后一个i的值.下面介绍几种方法可以获取到i的值 1.自定义属性: arr[i].index = i; 以 ...
- cf550C. Divisibility by Eight(结论)
题意 给出长度为$n$的字符串,判断是否能删除一些数后被$8$整除 Sol 神仙题啊Orz 结论: 若数字的后三位能被$8$整除,则该数字能被$8$整除 证明 设$x = 10000 * a_i + ...
- WireShark抓包命令
本机环回包 在进行通信开发的过程中,我们往往会把本机既作为客户端又作为服务器端来调试代码,使得本机自己和自己通信.但是wireshark此时是无法抓取到数据包的,需要通过简单的设置才可以. 具体方法如 ...
- k8s的secret基本概念及案例
secret相对于configMap,功能上是相似的但是secret是以其他编码方式去记录配置信息的,但是也可以被解读,只不过有技术门槛,不是那么容易就被解读.使用base64可以解码:echo ** ...
- 5-1 json模块
1.json.loads(json_str) 把字符串(json串)转成字典 import json # 解析json的 json_str = ''' {"name":" ...
- day03_基本数据类型基本运算
1.什么是数据类型 变量值才是我们存储的数据,所以数据类指的就是变量值的不同种类 2.为何数据要分类型? 变量值是用来保存现实世界中的状态的,那么针对不同的状态就应该用不同类型的数据去表示 3.如何用 ...
- 常用自写函数[更新ing]
int gcd (int x, int y)//最大公约数 { return y == 0 ? x : gcd( y , x % y ); } int lcm(int x, int y)//最小公倍数 ...
- 2 > 1 and 3 < 4 or 4 > 5 and 2 < 1
a,b,c,d,e=1,2,3,4,5 m = b >a and c < d n = d > e and b < a y = m or n info = ''' m is %s ...
- GIt-重置
master分支在版本库的引用目录(.git/refs)中体现为一个引用文件.git/refs/heads/master,其内容就是分支中最新提交的提交ID. $ cat .git/refs/head ...