zoukankan      html  css  js  c++  java
  • bzoj1023: [SHOI2008]cactus仙人掌图

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1023

    思路:类似树形DP记录一个f[i]表示最远(因为有环,所以这个定义是有一些限制条件的)

    先用点双缩点,每个环的信息可以挂到最高点上

    树上的差不多

    对于环上的,从一边扫过去,因为dis(i,j)有单调性,用单调队列搞一搞即可

    更详细的题解:http://ydcydcy1.blog.163.com/blog/static/21608904020131493113160/


    <span style="font-size:14px;">#include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define abs(a) (a<0?(-(a)):a)
    const int maxn=100010,maxm=500010;
    typedef unsigned int uint;
    using namespace std;
    int n,m,low[maxn],dfn[maxn],tim,sta[maxn],top,bnm[maxn],bcnt,ans,q[maxn],head,tail,a[maxn],f[maxn];bool vis[maxm];
    vector<int> bel[maxn],scc[maxn];
    
    struct Tgraph{
    	int pre[maxm],now[maxn],son[maxm],tot;
    	void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
    	void ins(int a,int b){add(a,b),add(b,a);}
    	void dp1(int x,int fa){
    		int id=x-n,cnt=scc[id].size(),top=0,siz=0;
    		for (int i=0;i<cnt;i++) a[++siz]=scc[id][i];
    		for (int i=0;i<cnt;i++) a[++siz]=scc[id][i];
    		head=1,tail=0;
    		for (int i=1;i<=siz;i++){
    			while (head<=tail&&i-q[head]>cnt/2) head++;
    			if (head<=tail) ans=max(ans,f[a[i]]+f[a[q[head]]]+i-q[head]);
    			while (head<=tail&&f[a[q[tail]]]-q[tail]<f[a[i]]-i) tail--;
    			q[++tail]=i;if (a[i]==fa&&!top) top=i-1;
    		}
    		for (int i=0;i<cnt;i++){
    			int d=abs(i-top);if (d>cnt/2) d=cnt-d;
    			f[x]=max(f[x],f[scc[id][i]]+d);
    		}
    		//printf("ans%d
    ",ans);
    	}
    	void dp2(int x,int fa){
    		int max1=0,max2=0;
    		for (int y=now[x];y;y=pre[y]) if (son[y]!=fa){
    			max2=max(max2,f[son[y]]+(son[y]<=n));
    			if (max2>max1) swap(max1,max2);
    		}
    		f[x]=max1;ans=max(ans,max1+max2);
    	}
    	void tree_dp(int x,int fa){
    		for (int y=now[x];y;y=pre[y]) if (fa!=son[y]) tree_dp(son[y],x);
    		if (x>n) dp1(x,fa);else dp2(x,fa);
    	}
    }g1,g2;
    
    void tarjan(int x,int fa){
    	dfn[x]=low[x]=++tim,sta[++top]=x;
    	for (int y=g1.now[x];y;y=g1.pre[y]) if (!vis[y]){
    		int v=g1.son[y];vis[y]=vis[y^1]=1;
    		if (!dfn[v]) tarjan(v,x),low[x]=min(low[x],low[v]);
    		else low[x]=min(low[x],dfn[v]);
    	}
    	if (low[x]==dfn[x]&&fa) top--,g2.ins(x,fa),bnm[x]++,bnm[fa]++;
    	if (low[x]==dfn[fa]){
    		int xx;bcnt++;
    		bel[fa].push_back(bcnt),scc[bcnt].push_back(fa);
    		do{xx=sta[top--],bel[xx].push_back(bcnt),scc[bcnt].push_back(xx);}while (x!=xx);
    	}
    }
    
    void rebuild(){
    	/*puts("");for (int i=1;i<=bcnt;i++){printf("i%d ",i);
    		for (uint j=0;j<scc[i].size();j++) printf("%d ",scc[i][j]);puts("");
    	}
    	puts("fuckpp
    
    
    
    ");*/
    	for (int i=1;i<=n;i++)
    		if (bnm[i]+bel[i].size()>=2)
    			for (uint j=0;j<bel[i].size();j++)
    				g2.ins(i,bel[i][j]+n);//,printf("%d %d
    ",i,bel[i][j]+n)
    }
    
    int main(){
    	scanf("%d%d",&n,&m),g1.tot=1;
    	for (int i=1,x,y,k;i<=m;i++){
    		scanf("%d%d",&k,&x);
    		for (int j=1;j<k;j++) scanf("%d",&y),g1.ins(x,y),x=y;
    	}
    	tarjan(1,0),rebuild(),g2.tree_dp(bcnt?n+1:1,0),printf("%d
    ",ans);
    	return 0;
    }
    </span>

  • 相关阅读:
    Kafka与RabbitMQ区别
    Illegal instruction 问题的解决方法
    Debian 6 , 十个串口为什么只识别到了 6个 剩下4 个被禁止了
    微信二次认证 C#
    修改XtraMessageBox的内容字体大小
    svn: E155017: Checksum mismatch while updating 校验错误的解决方法
    再生龙恢复分区后修复引导或debian linux修复引导 三部曲
    Clonezilla制作镜像时报错: errextfsclone.c:bitmap free count err
    我用windows live Writer 写个日志试试看
    Debian下签名无法验证
  • 原文地址:https://www.cnblogs.com/thythy/p/5493471.html
Copyright © 2011-2022 走看看