SP6779 GSS7 - Can you answer these queries VII
GSS7 - Can you answer these queries VII
题面翻译
题目描述
给定一棵树,有\(N(N \le 100000)\)个节点,每一个节点都有一个权值\(x_i (|x_i| \le 10000)\)
你需要执行\(Q (Q \le 100000)\)次操作:
1 a b
查询(a,b)
这条链上的最大子段和,可以为空(即输出\(0\))2 a b c
将(a,b)
这条链上的所有点权变为c
\((|c| <= 10000)\)
输入格式:
第一行一个整数\(N\)
接下来一行有\(N\)个整数表示\(x_i\)
接下来\(N-1\)行,每行两个整数\(u,v\)表示\(u\)和\(v\)之间有一条边相连
接下来一行一个整数\(Q\)
之后有\(Q\)行,每行诸如1 a b
或者2 a b c
输出格式
对于每一个询问,输出答案
输入样例
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
题目描述
Given a tree with N (N <= 100000) nodes. Each node has a interger value x_i (|x_i| <= 10000).
You have to apply Q (Q <= 100000) operations:
1. 1 a b : answer the maximum contiguous sum (maybe empty,will always larger than or equal to 0 ) from the path a->b ( inclusive ).
2. 2 a b c : change all value in the path a->b ( inclusive ) to c. (|c| <= 10000)
输入格式
first line consists one interger N.
next line consists N interger x_i.
next N-1 line , each consists two interger u,v , means that node u and node v are connected
next line consists 1 interger Q.
next Q line : 1 a b or 2 a b c .
输出格式
For each query, output one line the maximum contiguous sum.
样例 #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
Solution
GSS 系列第 \(7\) 题(别问我为什么前面只做了两道题就来看第 \(7\) 题了)
有区间推平操作不用珂朵莉树水一水真的太可惜了(逃
树上操作并不方便处理,所以用树剖把拆到链上进行解决。修改操作很简单,直接用珂朵莉树自带的assign
操作即可。问题是在于如何求解这个链上的最大子段和。
既然都用珂朵莉树了,那么求最大子段和就用最暴力的方法就可以了,即直接将区间提取出来,直接将区间和加入最大子段和内并尝试更新答案;如果此时的子段和已经为负数了,那么就将这个值赋为 \(0\),表示前面的子段全部舍弃(话说这部分应该是 pj 组内容吧,只不过是在珂朵莉树上实现的)。
在树剖过后的重链上跑这种珂朵莉树需要注意链的边界上的问题,因为链与链之间并不是独立的,边界的值是会相互影响,所以需要记下边界的子段和,在进入下一个重链的时候在这个子段和的基础上继续计算。
代码难度的话不算特别大,但是我也调了好一会才写出来,细节还是比较恼火的(才不是忘了调用树剖的两个 dfs 的呢,绝对不是 ~)。
Code
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
//#define int long long
using namespace std;
template<typename T> void read(T &k)
{
k=0;T flag=1;char b=getchar();
while (!isdigit(b)) {flag=(b=='-')?-1:1;b=getchar();}
while (isdigit(b)) {k=k*10+b-48;b=getchar();}
k*=flag;
}
template<typename T> void write(T k) {if (k<0) {putchar('-'),write(-k);return;}if (k>9) write(k/10);putchar(k%10+48);}
template<typename T> void writewith(T k,char c) {write(k);putchar(c);}
const int _SIZE=1e5;
int n,q,a[_SIZE+5];
struct EDGE{
int nxt,to;
}edge[(_SIZE<<1)+5];
int tot,head[_SIZE+5];
void AddEdge(int x,int y)
{
edge[++tot]=(EDGE){head[x],y};
head[x]=tot;
}
struct Node{
int l,r;
mutable int v;
Node(){}
Node(int l,int r=0,int v=0) : l(l),r(r),v(v) {}
bool operator< (const Node & a) const {return l<a.l;}
};
set<Node> ctlt;
auto split(int pos)
{
auto it=ctlt.lower_bound(Node(pos));
if (it!=ctlt.end() && it->l==pos) return it;it--;
int l=it->l,r=it->r,v=it->v;
ctlt.erase(it);
ctlt.insert(Node(l,pos-1,v));
return ctlt.insert(Node(pos,r,v)).first;
}
void assign(int l,int r,int v)
{
auto itr=split(r+1),itl=split(l);
ctlt.erase(itl,itr);
ctlt.insert(Node(l,r,v));
}
int query(int l,int r,int &basic)
{
int sum=basic,res=basic;
auto itr=split(r+1),itl=split(l);
itl--,itr--;
for (auto it=itr;it!=itl;it--)
{
sum+=it->v*(it->r-it->l+1);
res=max(res,sum);sum=max(sum,0);
}
basic=sum;
return res;
}
int son[_SIZE+5],id[_SIZE+5],siz[_SIZE+5],cnt;
int top[_SIZE+5],dep[_SIZE+5],fa[_SIZE+5];
void dfs1(int x,int f,int depth)
{
siz[x]=1,dep[x]=depth,fa[x]=f;
int maxson=-1;
for (int i=head[x];i;i=edge[i].nxt)
{
int twd=edge[i].to;
if (twd==f) continue;
dfs1(twd,x,depth+1);
siz[x]+=siz[twd];
if (siz[twd]>maxson) maxson=siz[twd],son[x]=twd;
}
}
int newx[_SIZE+5];
void dfs2(int x,int topf)
{
top[x]=topf;
id[x]=++cnt;
newx[cnt]=a[x];
if (!son[x]) return;
dfs2(son[x],topf);
for (int i=head[x];i;i=edge[i].nxt)
{
int twd=edge[i].to;
if (twd==fa[x] || twd==son[x]) continue;
dfs2(twd,twd);
}
}
void assignRange(int x,int y,int v)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
assign(id[top[x]],id[x],v);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
assign(id[x],id[y],v);
}
int queryRange(int x,int y)
{
int flag1=0,flag2=0,ans=0;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y),swap(flag1,flag2);
ans=max(ans,query(id[top[x]],id[x],flag1));
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y),swap(flag1,flag2);
swap(flag1,flag2);
ans=max(ans,query(id[x],id[y],flag1));
ans=max(ans,flag1+flag2);
return ans;
}
signed main()
{
read(n);
for (int i=1;i<=n;i++) read(a[i]);
for (int i=1;i<n;i++)
{
int u,v;read(u),read(v);
AddEdge(u,v),AddEdge(v,u);
}
dfs1(1,0,1);
dfs2(1,1);
for (int i=1;i<=n;i++) ctlt.insert(Node(i,i,newx[i]));
read(q);
for (int i=1;i<=q;i++)
{
int op,x,y,v;read(op),read(x),read(y);
if (op==2) read(v),assignRange(x,y,v);
else writewith(queryRange(x,y),'\n');
}
return 0;
}