题目:洛谷P3128。
题目大意:一棵n个点的树,每次将两个节点最短路径所覆盖的所有节点的流量加1。问你最后流量最大的节点的流量是多少。
解题思路:裸的树上差分。
对于每次增加流量,我们把两个节点的流量+1,它们的lca和lca的父亲的流量-1。
最后求一遍子树和,求出来每个节点的子树和就是该节点实际流量。
最后求最大值即可。
时间复杂度:树剖、倍增LCA $O(m\log_2 n)$,Tarjan LCA $O(n+m)$。
我采用Tarjan算法,288ms。
C++ Code:
#include<cstdio> #include<cstring> #include<vector> #include<cctype> #define N 50005 using namespace std; int n,m,ne=0,nq=0; bool vis[N],instack[N]; int f[N],head[N],que[N],a[N],zx[N]; #define C c=getchar() inline int readint(){ char C; bool b=false; while(!isdigit(c))b=c==‘-‘,C; int d=0; while(isdigit(c)){ d=d*10+c-‘0‘; C; } return (b)?(-d):d; } struct query{ int same,nxt,to,num; bool flag; }q[N<<5]; struct edge{ int to,nxt; }e[N<<5]; void add_edge(int x,int y){ e[++ne].to=y; e[ne].nxt=head[x]; head[x]=ne; e[++ne].to=x; e[ne].nxt=head[y]; head[y]=ne; } void add_que(int x,int y,int z){ q[++nq].to=y; q[nq].same=nq+1; q[nq].num=z; q[nq].nxt=que[x]; que[x]=nq; q[++nq].to=x; q[nq].same=nq-1; q[nq].num=z; q[nq].nxt=que[y]; que[y]=nq; } int find(int x){ if(f[x]==x)return x; return f[x]=find(f[x]); } void tarjan(int root){ instack[root]=true; for(int i=head[root];i;i=e[i].nxt){ int v=e[i].to; if(instack[v])continue; tarjan(v); f[v]=root; vis[v]=true; } for(int i=que[root];i;i=q[i].nxt) if(vis[q[i].to]&&!q[i].flag){ int p=find(q[i].to); --a[p]; --a[zx[p]]; q[i].flag=q[q[i].same].flag=true; } instack[root]=false; } void dfs(int now){ instack[now]=true; for(int i=head[now];i;i=e[i].nxt) if(!instack[e[i].to]){ dfs(e[i].to); a[now]+=a[e[i].to]; } } void dfs2(int now){ instack[now]=true; for(int i=head[now];i;i=e[i].nxt) if(!instack[e[i].to]){ zx[e[i].to]=now; dfs2(e[i].to); } } int main(){ n=readint(),m=readint(); memset(vis,0,sizeof(vis)); memset(instack,0,sizeof instack); for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<n;i++){ int u=readint(),v=readint(); add_edge(u,v); } memset(a,0,sizeof a); zx[1]=0; dfs2(1); memset(instack,0,sizeof instack); for(int i=1;i<=m;i++){ int x=readint(),y=readint(); ++a[x]; ++a[y]; if(x!=y) add_que(x,y,i);else --a[x],--a[zx[x]]; } tarjan(1); memset(instack,0,sizeof instack); dfs(1); int max=0; for(int i=1;i<=n;i++) if(max<a[i])max=a[i]; printf("%d\n",max); return 0; }
时间: 2024-09-27 14:17:14