Loading

基环树

基环树

这是一个有n个点,n条边的连通图,简单来说就是一棵树加了一条边。

两种常见思路:

  1. 去掉环上的一条边使之成为一棵树,再想办法把去掉这条边的影响给补上,简单来说就是划分样板空间。
  2. 把环缩成一个大点,把所有信息集中在环上,再在环上进行处理。常见的是环上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;
}
posted @ 2021-04-13 17:01  hyl天梦  阅读(78)  评论(0编辑  收藏  举报