P1620小白逛公园加强版

背景

Crash觉得小白逛公园有点简单了,稍微加强了一下……

描述

小新经常陪小白去公园玩,也就是所谓的遛狗啦……在小新家附近有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)

输出格式

对于每次询问,输出最大连续和。(用空格隔开,最后要有换行符)

样例1

样例输入1[复制]

 
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

样例输出1[复制]

 
5 9

限制

小数据1s,大数据2s
(时间是足够的……)

提示

对于30%的数据:n,m <= 100
对于70%的数据:n,m <= 50000
对于100%的数据:n,m <= 100000

 
 
 
 
虽然这道题看起来不是很好写,但是实际上写起来还是很容易的,不过只是这道题需要注意的细节比较多,大概写完调试了有一个星期左右。。。。主要是因为一些比较沙比的错误。。。在zyf神犇的帮助下艰难的A掉了这道题。。。
这道题其实就是一道比较裸的树链剖分。。。因为我们都知道树链剖分是依托于数据结构来实现的。。那么也就是说数据结构支持什么样的操作,树链剖分就支持什么样的操作。。。相信这道题的弱化版大家都做过。。。没有的话我的博客里也有相关的题解。。。这道题如果不在树上进行的话,就是用线段树查询区间最大连续和+区间修改。。。
只需记录lmax,rmax,max,sum即可。。。不过这里需要吐槽的是我没有get小白逛公园的正确做法。。。我的做法是比较取巧,直接查询区间的lmax,rmax,max然后进行操作。。。不过我个人认为这道题实际上是需要我们写一个merge操作。。。因为实际上我们对于一段连续的区间上的操作实际上是把一段区间分成不同的子区间然后进行合并。。。那么对于树链剖分我们查询出的结果实际上就是一个一个独立的子区间,然后我们只需要对于在树上相邻的子区间进行合并即可。。。这大概就是这道题的做法了。。。说起来似乎也没什么难得。。。不过里面需要注意的细节很多。。。
主要一是对于合并操作我们要判断哪一段要作为左边的区间哪一个要作为右边的区间;二是我们要对树链剖分所得到的区间进行区分,哪一个是lca左边的哪一个是lca右边的区间。。。然后每次合并都是把之前的结果合并成一个大的区间,同时也要注意究竟是要把大区间作为左边的还是右边的。。。这样一说似乎又变得很麻烦。。。。=,=
具体我们来看核心代码。。
int solvemax(int x,int y){
	tree res1,res2;//一个是lca左边的,一个是lca右边的
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y),swap(res1,res2);//交换x,y时也要交换res1,res2
		res1=merge(query(1,p[top[x]],p[x]),res1);//合并区间
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])swap(x,y),swap(res1,res2);
	res1=merge(query(1,p[y],p[x]),res1);
	swap(res1.lmax,res1.rmax);
    res1=merge(res1,res2);
	return res1.mx;
}

  大概就是这一段代码需要注意的地方比较多。。。写完之后就会发现自己对树链剖分有了更加深入的了解(似乎是一句废话。。。。

这道题还需要注意的是lazytag的标记问题。。。一般都是直接赋值为0。。。不过这道题有可能会修改为0。。。所以这里要注意值不能为0。。。

大概还要记住要return!!!! 

然后是代码。。。。zyf神犇告诉我这是一道码农题。。。不过代码还不到200行(大雾。。。。。不过p党似乎有写300+。。真是太神辣!!!

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<algorithm>
  7 #include<string>
  8 #include<map>
  9 #include<queue>
 10 #include<vector>
 11 #include<set>
 12 #define mod 1000000007
 13 #define inf 1000000010
 14 #define maxn 100005
 15 #define maxm 100005*2
 16 #define eps 1e-10
 17 #define ll long long
 18 #define for0(i,n) for(int i=0;i<=(n);i++)
 19 #define for1(i,n) for(int i=1;i<=(n);i++)
 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 22 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
 23 using namespace std;
 24 int read(){
 25     int x=0,f=1;char ch=getchar();
 26     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 27     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 28     return x*f;
 29 }
 30 struct tree{
 31     int l,r,sum,mx,lmax,rmax,lazy;
 32     tree(){lmax=rmax=mx=sum=0;lazy=-inf;l=r=0;}
 33 }f[maxn*4];
 34 struct edge{
 35     int go,next;
 36 }e[maxm];
 37 int head[maxn],w[maxn],top[maxn],fa[maxn],p[maxn],son[maxn],s[maxn],dep[maxn],a[maxn],tot,cnt;
 38 
 39 void pushup(int i){
 40     f[i].sum=(f[(i<<1)+1].sum+f[i<<1].sum);
 41     f[i].lmax=max(0,max(f[i<<1].lmax,f[i<<1].sum+f[(i<<1)+1].lmax));
 42     f[i].rmax=max(0,max(f[(i<<1)+1].rmax,f[(i<<1)+1].sum+f[i<<1].rmax));
 43     f[i].mx=max(0,max(f[i<<1].mx,max(f[(i<<1)+1].mx,f[i<<1].rmax+f[(i<<1)+1].lmax)));
 44 }
 45 
 46 void update(int i,int x){
 47     f[i].sum=(f[i].r-f[i].l+1)*x; 
 48     f[i].lmax=f[i].rmax=f[i].mx=max(0,f[i].sum);
 49     f[i].lazy=x;
 50     return;
 51 }
 52 
 53 void pushdown(int i){
 54     if(f[i].lazy==-inf)return;
 55     else{
 56         update(i<<1,f[i].lazy);
 57         update((i<<1)+1,f[i].lazy);
 58         f[i].lazy=-inf;
 59     }
 60 }
 61 void build(int i,int left,int right){
 62     int mid=(left+right)/2;
 63     f[i].l=left;f[i].r=right;f[i].lmax=f[i].mx=f[i].rmax=0;f[i].lazy=-inf;
 64     if(left==right){
 65         f[i].sum=a[left];
 66         f[i].lmax=f[i].rmax=f[i].mx=max(0,a[left]);
 67         return;
 68     }
 69     build(i<<1,left,mid);
 70     build((i<<1)+1,mid+1,right);
 71     pushup(i);
 72 }
 73  
 74 void change(int i,int left,int right,int v){
 75     int mid=(f[i].l+f[i].r)/2;
 76     if(f[i].l==left&&f[i].r==right){
 77         update(i,v);
 78         return;
 79     }
 80     pushdown(i);
 81     if(mid>=right)change(i<<1,left,right,v);  
 82     else if(mid<left)change((i<<1)+1,left,right,v);
 83     else change(i<<1,left,mid,v),change((i<<1)+1,mid+1,right,v);
 84     pushup(i);
 85 }
 86 
 87 tree merge(tree res1,tree res2){
 88     tree res;
 89     res.sum=res1.sum+res2.sum;
 90     res.lmax=max(0,max(res1.lmax,res1.sum+res2.lmax));
 91     res.rmax=max(0,max(res2.rmax,res2.sum+res1.rmax));
 92     res.mx=max(0,max(res1.rmax+res2.lmax,max(res1.mx,res2.mx)));
 93     return res;
 94 }
 95 
 96 tree query(int i,int left,int right){
 97     int mid=(f[i].l+f[i].r)>>1;
 98     if(f[i].l==left&&f[i].r==right)return f[i];
 99     pushdown(i);
100     if(mid>=right)return query(i<<1,left,right);
101     else if(mid<left)return query((i<<1)+1,left,right);
102     else return merge(query(i<<1,left,mid),query((i<<1)+1,mid+1,right));
103 }
104 
105 void insert(int u,int v){
106     e[++tot].go=v;e[tot].next=head[u];head[u]=tot;
107 }
108 void ins(int u,int v){
109     insert(u,v);insert(v,u);
110 }
111 void dfs(int x){
112     s[x]=1;
113     for(int y=son[x]=0,i=head[x];i;i=e[i].next){
114         if(dep[y=e[i].go]==0){
115             dep[y]=dep[x]+1;fa[y]=x;dfs(y);
116             s[x]+=s[y];if(s[y]>s[son[x]])son[x]=y;
117         }
118     }
119 }
120 void dfs2(int x,int chain){
121     p[x]=++cnt;top[x]=chain;a[p[x]]=w[x];
122     if(son[x])dfs2(son[x],chain);
123     for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
124         if(y!=fa[x]&&y!=son[x])dfs2(y,y);
125 }
126 void solvechange(int x,int y,int v){
127     while(top[x]!=top[y]){
128         if(dep[top[x]]<dep[top[y]])swap(x,y);
129         change(1,p[top[x]],p[x],v);
130         x=fa[top[x]];
131     }
132     if(dep[x]>dep[y])swap(x,y);
133     change(1,p[x],p[y],v);
134 }
135 int solvemax(int x,int y){
136     tree res1,res2;
137     while(top[x]!=top[y]){
138         if(dep[top[x]]<dep[top[y]])swap(x,y),swap(res1,res2);
139         res1=merge(query(1,p[top[x]],p[x]),res1);
140         x=fa[top[x]];
141     }
142     if(dep[x]<dep[y])swap(x,y),swap(res1,res2);
143     res1=merge(query(1,p[y],p[x]),res1);
144     swap(res1.lmax,res1.rmax);
145     res1=merge(res1,res2);
146     return res1.mx;
147 }
148 int main(){
149     //freopen("input.txt","r",stdin);
150     //freopen("output.txt","w",stdout);
151     int n=read();dep[1]=1;
152     for1(i,n)w[i]=read();
153     for1(i,n-1){
154         int u=read(),v=read();
155         ins(u,v);
156     }
157     dfs(1);dfs2(1,1);
158     build(1,1,n);
159     n=read();
160     for1(i,n){
161         int x=read();
162         if(x==1){
163             int y=read(),z=read();
164             printf("%d ",solvemax(y,z));
165         }
166         else{
167             int y=read(),z=read();x=read();
168             solvechange(y,z,x);
169         }
170     }
171     printf("\n");
172     return 0;
173 }
View Code

 

 
posted @ 2016-01-22 08:44  HTWX  阅读(159)  评论(0编辑  收藏  举报