题目链接: http://xcacm.hfut.edu.cn/problem.php?id=1103
题目大意:链更新。链查询,求树链的最大子段和。(子段可以为空)
解题思路:
将所有Query离线存储,并且注明哪个是更新,哪个是查询。
Tarjan离线处理中,记录每个结点的前驱,p[v]=u。
若更新,从u点回溯到LCA,从v点回溯到LCA,逐个修改。
若查询,将u点回溯到LCA,LCA,v点回溯到LCA的倒序拼成一个序列,求最大子段和。
值得注意的是,子段和全为负值的时候,ans=max(0,ans),即不要任何插线板(原题意思不明)。
#include "cstdio" #include "cstring" #include "vector" #include "algorithm" using namespace std; #define maxn 100005 #define inf 0x3f3f3f3f int head[maxn],qhead[maxn],lag[maxn],kth[maxn],tot1,tot2,f[maxn],vis[maxn],ancestor[maxn],p[maxn],s1[maxn],s2[maxn]; bool isUpdate[maxn]; struct Edge { int to,next; }e[maxn*2]; struct Query { int from,to,next,idx,c; }q[maxn*2]; void addedge(int u,int v) { e[tot1].to=v; e[tot1].next=head[u]; head[u]=tot1++; } void addquery(int u,int v,int idx,int c=inf) { q[tot2].from=u; q[tot2].to=v; q[tot2].next=qhead[u]; q[tot2].idx=idx; if(c!=inf) q[tot2].c=c; qhead[u]=tot2++; } int find(int x) {return x!=f[x]?f[x]=find(f[x]):x;} void Union(int u,int v) { u=find(u),v=find(v); if(u!=v) f[v]=u; } void LCA(int u) { vis[u]=true; f[u]=u; for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; if(!vis[v]) { p[v]=u; LCA(v); Union(u,v); } } for(int i=qhead[u];i!=-1;i=q[i].next) { int v=q[i].to; if(vis[v]) ancestor[q[i].idx]=find(v); //or storage e[i].lca=e[i^1].lca=find(v) } } int sum(int num) { s2[0]=s1[0]; int Max=s2[0]; for(int i=1; i<num; i++) { if(s2[i-1]>0) s2[i]=s2[i-1]+s1[i]; else s2[i]=s1[i]; if(s2[i]>Max) Max=s2[i]; } return max(0,Max); } int main() { //freopen("in.txt","r",stdin); int T,n,m,u,v,c,cmd,qcnt=0; scanf("%d",&n); tot1=tot2=0; memset(head,-1,sizeof(head)); memset(qhead,-1,sizeof(qhead)); memset(vis,0,sizeof(vis)); memset(isUpdate,0,sizeof(isUpdate)); for(int i=1;i<=n;i++) scanf("%d",&lag[i]); for(int i=0; i<n-1; i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } scanf("%d",&m); for(int i=0; i<m; i++) { scanf("%d",&cmd); if(cmd==2) { scanf("%d%d%d",&u,&v,&c); addquery(u,v,i,c); addquery(v,u,i,c); isUpdate[i]=true; } else { scanf("%d%d",&u,&v); addquery(u,v,i); addquery(v,u,i); } } LCA(1); vector<int> ans; for(int i=0; i<tot2; i=i+2) { int u=q[i].from,v=q[i].to,idx=q[i].idx; int ed=ancestor[idx],cnt=0; if(isUpdate[qcnt]) { int c=q[i].c; while(u!=ed) lag[u]=c,u=p[u]; lag[ed]=c; while(v!=ed) lag[v]=c,v=p[v]; } else { while(u!=ed) s1[cnt++]=lag[u],u=p[u]; s1[cnt++]=lag[ed]; vector<int> rev; while(v!=ed) rev.push_back(lag[v]),v=p[v]; for(int j=rev.size()-1; j>=0; j--) s1[cnt++]=rev[j]; int x=sum(cnt); ans.push_back(x); } qcnt++; } for(int i=0;i<ans.size()-1;i++) printf("%d ",ans[i]); printf("%d\n",ans[ans.size()-1]); }