基环树
基环树
这是一个有n个点,n条边的连通图,简单来说就是一棵树加了一条边。
两种常见思路:
- 去掉环上的一条边使之成为一棵树,再想办法把去掉这条边的影响给补上,简单来说就是划分样板空间。
- 把环缩成一个大点,把所有信息集中在环上,再在环上进行处理。常见的是环上dp。
前者是基环树最大独立集的基本思路,后者是基环树最长链的基本思路。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<deque>
#include<cstdlib>
#include<ctime>
#define dd double
#define ld long double
#define ll long long
#define int long long
#define ull unsigned long long
#define N 2100000
#define M 3002000
using namespace std;
const int INF=0x3f3f3f3f;
inline int Max(int a,int b){
return a>b?a:b;
}
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct edge{
int to,next;
inline void intt(int to_,int ne_){
to=to_;next=ne_;
}
};
edge li[N];
int head[N],tail;
inline void add(int from,int to){
li[++tail].intt(to,head[from]);
head[from]=tail;
}
int n,p[N];
dd k;
int fa[N],p1,p2,p1p,p2p;
bool vis[N];
inline void dfs(int k,int fat){
fa[k]=fat;vis[k]=1;
for(int x=head[k];x;x=li[x].next){
int to=li[x].to;
if(to==fat) continue;
if(!vis[to]) dfs(to,k);
else p1=k,p2=to;
}
}
int f[N][2][2],ans;// 1 choose; 0 do not choose
inline void dp(int k,int ci){
vis[k]=ci;
for(int x=head[k];x;x=li[x].next){
int to=li[x].to;
if(to==fa[k]||vis[to]==ci) continue;
vis[to]=ci;
dp(to,ci);
f[k][1][ci]+=f[to][0][ci];
f[k][0][ci]+=Max(f[to][0][ci],f[to][1][ci]);
}
f[k][1][ci]+=p[k];
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
p[i]=read();
int to=read();
add(i,to);add(to,i);
}
for(int i=1;i<=n;i++){
if(vis[i]) continue;
dfs(i,0);
p1p=p[p1];p2p=p[p2];
p[p1]=-INF;dp(i,0);
p[p1]=p1p;p[p2]=-INF;dp(i,1);
p[p2]=p2p;
ans+=Max(f[i][1][0],Max(f[i][1][1],Max(f[i][0][0],f[i][0][1])));
}
printf("%lld",ans);
return 0;
}
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<deque>
#include<cstdlib>
#include<ctime>
#define dd double
#define ld long double
#define ll long long
#define int long long
#define ull unsigned long long
#define N 1001000
#define M 2002000
using namespace std;
const int INF=0x3f3f3f3f;
inline int Max(int a,int b){
return a>b?a:b;
}
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct edge{
int to,next,w;
inline void intt(int to_,int ne_,int w_){
to=to_;next=ne_;w=w_;
}
};
edge li[M];
int head[N],taill=1;
inline void add(int from,int to,int w){
li[++taill].intt(to,head[from],w);
head[from]=taill;
}
int n;
int s[N],d[N],rk[N],id[N],prep[N],pree[N],tail,ans,s2[N];
bool vis[M],if_huan[N],visp[N];
inline void collect(int u,int v,int nowe){
vis[nowe]=1;vis[nowe^1]=1;
for(int k=v;k!=u;k=prep[k]){
rk[++tail]=k;if_huan[k]=1;
d[tail]=li[pree[k]].w;id[k]=tail;
}
rk[++tail]=u;d[tail]=li[nowe].w;if_huan[u]=1;id[u]=tail;
}
inline void dfs1(int k){
visp[k]=1;
for(int x=head[k];x;x=li[x].next){
int to=li[x].to;
if(!vis[x]&&!visp[to]){
vis[x]=1;vis[x^1]=1;
prep[to]=k;pree[to]=x;dfs1(to);
// vis[x]=0;vis[x^1]=0;
}
else if(!vis[x]&&visp[to]){
// printf("ENTER\n");
// printf("k:%d\n",k);
collect(to,k,x);
}
}
// visp[k]=0;
}
inline void dfs2(int k,int fa){
for(int x=head[k];x;x=li[x].next){
int to=li[x].to,w=li[x].w;
if(if_huan[to]||to==fa) continue;
dfs2(to,k);
ans=Max(ans,s[k]+s[to]+w);
s[k]=Max(s[k],s[to]+w);
}
}
int q[N],l,r,f[N],sum[N],failans;
signed main(){
n=read();
for(int i=1;i<=n;i++){
int to=read(),w=read();
add(i,to,w);add(to,i,w);
}
// printf("build\n");
for(int i=1;i<=n;i++){
if(visp[i]) continue;
l=r=0;ans=0;
tail=0;
dfs1(i);
// printf("over dfs1\n");
for(int i=1;i<=tail;i++) dfs2(rk[i],0);
// printf("nowans:%d\n",ans);
// printf("tail:%d\n",tail);
for(int i=1;i<=tail;i++) s2[i]=s[rk[i]];
for(int i=tail+1;i<=tail*2;i++) s2[i]=s2[i-tail],d[i]=d[i-tail];
for(int i=1;i<=tail*2;i++) sum[i]=sum[i-1]+d[i];
// printf("rk:\n");for(int i=1;i<=tail;i++) printf("i:%d rk[i]:%d\n",i,rk[i]);
// printf("s2: ");for(int i=1;i<=2*tail;i++) printf("%d ",s2[i]);printf("\n");
// printf("d: ");for(int i=1;i<=2*tail;i++) printf("%d ",d[i]);printf("\n");
// printf("sum: ");for(int i=1;i<=2*tail;i++) printf("%d ",sum[i]);printf("\n");
q[++r]=0;
for(int i=1;i<=tail*2;i++){
while(l<r&&q[l+1]<=i-tail) l++;
if(q[l+1]!=0) f[i]=sum[i-1]-sum[q[l+1]-1]+s2[i]+s2[q[l+1]];
ans=Max(ans,f[i]);
// printf("i:%d f[i]:%d\n",i,f[i]);
while(l<r&&s2[q[r]]+sum[i-1]-sum[q[r]-1]<=s2[i]) r--;
q[++r]=i;
}
failans+=ans;
}
printf("%lld",failans);
return 0;
}