zoukankan      html  css  js  c++  java
  • 【题解】Luogu P4381 [IOI2008]Island

    原题传送门

    题意:求基环树森林的直径(所有基环树直径之和)

    首先,我们要对环上所有点的子树求出它们的直径和最大深度。然后,我们只用考虑在环上至少经过一条边的路径。那么,这种路径在环上一定有起始点和终点。(假设路径是从起始点开始,按顺时针方向走达到终点)

    不妨枚举这段路径在环上的终点。由于规定了这个点和方向,我们就可以拆环了。然后是一个经典的技巧,把环上元素复制一遍,就可以枚举全部拆环方案。设环上有l个结点。那么,我们枚举终点,就相当于在长度为2l的数组上不断滑动一个长度为l的区间

    剩下的问题与基环树已经没什么关系了。设环上边权的前缀和为sum,环上结点的子树的最大深度为dep

    那么,在环上起始点为i,终点为j的路径能得到的长度就是(sum_j−sum_i+dep_j+dep_i)。既然枚举了j,我们在滑动区间时就只用维护(dep_i−sum_i)的最大值就可以了。这个可以用单调队列实现

    时间复杂度O(n)

    #include <bits/stdc++.h>
    #define N 1000005
    #define ll long long
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register ll x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[25];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    inline ll Max(register ll a,register ll b)
    {
    	return a>b?a:b;
    }
    struct edge{
    	int to,next,w;
    }e[N<<1];
    int head[N],cnt=0,du[N];
    inline void add(register int u,register int v,register int w)
    {
    	e[++cnt]=(edge){v,head[u],w};
    	head[u]=cnt,++du[v];
    }
    int n,t,vis[N],v[N],qu[N<<1];
    ll d[N],f[N],ans,a[N<<1],b[N<<1];
    inline void bfs(register int u,register int ti)
    {
    	vis[u]=ti;
    	queue<int> q;
    	q.push(u);
    	while(!q.empty())
    	{
    		int v=q.front();
    		q.pop();
    		for(register int i=head[v];i;i=e[i].next)
    			if(!vis[e[i].to])
    			{
    				q.push(e[i].to);
    				vis[e[i].to]=ti;
    			}
    	}
    }
    inline void topsort()
    {
    	queue<int> q;
    	for(register int i=1;i<=n;++i)	
    		if(du[i]==1)
    			q.push(i);
    	while(!q.empty())
    	{
    		int v=q.front();
    		q.pop();
    		for(register int i=head[v];i;i=e[i].next)
    			if(du[e[i].to]>1)
    			{
    				d[vis[v]]=Max(d[vis[v]],f[v]+f[e[i].to]+e[i].w);
    				f[e[i].to]=Max(f[e[i].to],f[v]+e[i].w);
    				if((--du[e[i].to])==1)
    					q.push(e[i].to);
    			}
    	}
    }
    inline void dp(register int ti,register int x)
    {
    	int m=0,i,l=0,r,y=x;
    	do{
    		a[++m]=f[y];
    		du[y]=1;
    		for(i=head[y];i;i=e[i].next)
    			if(du[e[i].to]>1)
    			{
    				b[m+1]=b[m]+e[i].w;
    				y=e[i].to;
    				break;
    			}
    	}while(i);
    	if(m==2)
    	{
    		for(i=head[y];i;i=e[i].next)
    			if(e[i].to==x)
    				l=Max(l,e[i].w);
    		d[ti]=Max(d[ti],f[x]+f[y]+l);
    		return;
    	}
    	for(i=head[y];i;i=e[i].next)
    		if(e[i].to==x)
    		{
    			b[m+1]=b[m]+e[i].w;
    			break;
    		}
    	for(register int i=1;i<m;++i)
    		a[m+i]=a[i],b[m+i]=b[m+1]+b[i];
    	qu[l=r=1]=1;
    	for(i=2;i<m<<1;++i)
    	{
    		while(l<=r&&i-qu[l]>=m)
    			++l;
    		d[ti]=Max(d[ti],a[i]+a[qu[l]]+b[i]-b[qu[l]]);
    		while(l<=r&&a[qu[r]]-b[qu[r]]<=a[i]-b[i])
    			--r;
    		qu[++r]=i;
    	}
    }
    int main()
    {
    	n=read();
    	for(register int i=1;i<=n;++i)
    	{
    		int v=read(),w=read();
    		add(i,v,w),add(v,i,w);
    	}
    	for(register int i=1;i<=n;++i)
    		if(!vis[i])
    			bfs(i,++t);
    	topsort();
    	for(register int i=1;i<=n;++i)
    		if(du[i]>1&&!v[vis[i]])
    		{
    			v[vis[i]]=1;
    			dp(vis[i],i);
    			ans+=d[vis[i]];
    		}
    	write(ans);
    	return 0;
    }
    
    
  • 相关阅读:
    virtualBox中有线和无线两种情况下centos虚拟机和本地机互ping的方案
    微信小程序支付Java服务端开发源码,及那些你不知道的坑(一)
    SpringCloud微服务项目实战
    SpringCloud微服务项目实战
    SpringCloud微服务项目实战,服务注册与发现(附面试题)
    Spring Cloud微服务项目实战--Eureka服务搭建
    SpringBoot+SpringCloud面试总结都在这里
    SpringBoot 实现系统控制并发登录人数
    Java中大量if...else语句的消除替代方案
    SpringBoot基于数据库的定时任务实现
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/10507469.html
Copyright © 2011-2022 走看看