[树上最长链][tarjan][单调队列][环上前缀和] Jzoj P5905 黑暗之魂(darksoul)
题解
- 题目大意就是在一棵有环的树上求树上最长链
- 首先,先不考虑环,把所有在换上的子树的树上最长链求出来(PS:答案也有可能是一棵子树上的最长链+次大链)
- 那么我们如何找到在环上的子树呢
- 因为题目说是n条边,那么就是只有一个环,这样的话直接用tarjan就可以求出来了
- 考虑加上环,先说明一个东西:题目中的主人公也是有脑子的,不会绕远路
- 也就是在环上,只会走较短的劣弧不会走优弧,
- 就可以用单调队列维护在比圆的周长的一半要小的部分中的递减序列
- 链的长度的公式:len[x]+len[i]+pre[x]-len[i]
- 因为还有比圆的周长的一半还要大的,所以要把数组倍长
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 const int maxn=1e7+10; 8 int n,cnt,k,bel,tot,head1,tail,boo,head[maxn],dfn[maxn],low[maxn],belong[maxn]; 9 bool vis[maxn]; 10 int root[maxn],q[maxn*2]; 11 long long ans,f[maxn*2],len[maxn*2],pre[maxn*2],dis[maxn*2],mid; 12 struct edge{ int v,to,from; }e[maxn*2]; 13 struct node{ int x,y,v; }a[maxn]; 14 vector<int>Q; 15 void insert(int a,int b,int c) 16 { 17 e[++cnt].to=b; e[cnt].from=head[a]; e[cnt].v=c; head[a]=cnt; 18 e[++cnt].to=a; e[cnt].from=head[b]; e[cnt].v=c; head[b]=cnt; 19 } 20 void dfs(int x,int fa) 21 { 22 long long max1=0,max2=0,l=0; 23 for (int i=head[x];i;i=e[i].from) 24 if (belong[e[i].to]!=k&&e[i].to!=fa) 25 { 26 dfs(e[i].to,x); 27 l=f[e[i].to]+e[i].v; 28 if (l>max1) max2=max1,max1=l; else max2=max(l,max2); 29 } 30 ans=max(max1+max2,ans); 31 f[x]=max1; 32 } 33 void tarjan(int x,int fa) 34 { 35 dfn[x]=low[x]=++cnt,vis[x]=1; 36 Q.push_back(x); 37 for (int i=head[x];i;i=e[i].from) 38 if (e[i].to!=fa) 39 { 40 if (!dfn[e[i].to]) 41 { 42 tarjan(e[i].to,x); 43 low[x]=min(low[x],low[e[i].to]); 44 } 45 else if (vis[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); 46 } 47 if (low[x]==dfn[x]) 48 { 49 bel++; 50 int y=0,boo=0; 51 if (Q.back()!=x) boo=1,k=bel; 52 while (y!=x) 53 { 54 y=Q.back(),Q.pop_back(); 55 belong[y]=bel,vis[y]=0; 56 if (boo) root[++tot]=y; 57 } 58 } 59 } 60 bool cmp(node a,node b) { return a.x==b.x?(a.y==b.y?a.v<b.v:a.y<b.y):a.x<b.x; } 61 int main() 62 { 63 freopen("darksoul.in","r",stdin),freopen("darksoul.out","w",stdout); 64 scanf("%d",&n); 65 for (int i=1;i<=n;i++) 66 { 67 scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v); 68 if (a[i].x>a[i].y) swap(a[i].x,a[i].y); 69 } 70 sort(a+1,a+n+1,cmp); 71 bool boo=false; 72 for (int i=1;i<=n;i++) 73 if (a[i].x==a[i].y||a[i].x==a[i-1].x&&a[i].y==a[i-1].y) boo=true; 74 else insert(a[i].x,a[i].y,a[i].v); 75 if (boo) 76 { 77 k=-1,dfs(1,0),printf("%lld",ans+1); 78 return 0; 79 } 80 cnt=0,tarjan(1,0); 81 for (int i=1;i<=tot;i++) dfs(root[i],0),len[i]=f[root[i]]; 82 for (int i=1;i<=tot;i++) 83 for (int j=head[root[i]];j;j=e[j].from) 84 if (e[j].to==root[i!=1?i-1:tot]) 85 { 86 dis[i]=(long long)e[j].v; 87 break; 88 } 89 for (int i=1;i<=tot;i++) dis[i+tot]=dis[i],len[i+tot]=len[i]; 90 for (int i=1;i<=tot*2;i++) pre[i]=pre[i-1]+dis[i]; 91 mid=pre[tot]; 92 head1=tail=q[head1]=1; 93 for (int i=2;i<=2*tot;i++) 94 { 95 while (head1<=tail&&(pre[i]-pre[q[head1]]>mid/2)) head1++; 96 if (head1<=tail) ans=max(ans,len[q[head1]]+len[i]+pre[i]-pre[q[head1]]); 97 while (head1<=tail&&(len[i]-pre[i]>=len[q[tail]]-pre[q[tail]])) tail--; 98 q[++tail]=i; 99 } 100 printf("%lld",ans+1); 101 }