zoukankan      html  css  js  c++  java
  • uoj#84. 【UR #7】水题走四方

    题目描述

    n<=5*10^6

    题解

    好题

    直接贪心/dp是假的,反例考虑两条长链+上面的一些短链

    硬点本体只会往下走,分身负责清理掉伸出去的链,最后留下一条最长链一起走下去

    dp方程式见官方题解,直接做是n^2的

    一些性质:

    ①留下的链一定在本体所在点上,否则可以再分一段

    ②转移过来的点之间的距离要不大于留下的链长,否则可以再分一段

    然后暴力维护不同长链深度的即可O(n√n),因为只有√n种

    更强的性质:

    只需要从最近的祖先且除当前点所在子树的最长链深度>=当前点的点转移+当前点的父亲即可

    证明考虑如果有两个满足的点uv,其中u在v上方,则从u->当前点和u->v->当前点所一起走的路程一样,并且后者其余叶子到他的距离减少了

    当前点的父亲是因为性质②要传递

    具体实现长链剖分,先走轻儿子并把重儿子的深度加上去,再走重儿子并把轻儿子的深度加上去

    超过了范围就直接弹栈,正确性证明:

    一个点一定能被最近且满足条件的点更新(最近的点不会被弹掉),如果两点之间没有分支则显然可以

    否则如果当前点在分支点的重子树里,由于前提条件存在所以轻子树的深度不会超过当前点的深度,更不会超过转移点的深度,所以走下去不会弹掉,如果在轻子树里就不满足前提条件

    时间复杂度O(n)

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define min(a,b) (a<b?a:b)
    #define max(a,b) (a>b?a:b)
    #define ll long long
    //#define file
    using namespace std;
    
    int a[5000001][2],ls[5000001],fa[5000001],p[5000001],P[5000001][2],d[5000001],D[5000001],nx[5000001],n,i,j,k,l,len,tot;
    ll size[5000001],sum[5000001],f[5000001],dp[5000001],ans;
    char ch;
    
    void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
    void dfs(int t)
    {
    	int i;
    	if (!ls[t]) size[t]=1;
    	
    	for (i=ls[t]; i; i=a[i][1])
    	{
    		dp[a[i][0]]=dp[t]+1,dfs(a[i][0]);
    		size[t]+=size[a[i][0]];
    		sum[t]+=sum[a[i][0]]+size[a[i][0]];
    		
    		if (d[t]<d[a[i][0]]+1) D[t]=d[t],d[t]=d[a[i][0]]+1,nx[t]=a[i][0];
    		else D[t]=max(D[t],d[a[i][0]]+1);
    	}
    }
    void Dfs(int Fa,int t)
    {
    	int i;
    	while (tot && dp[P[tot][0]]+P[tot][1]<dp[t]) --tot;
    	if (t>1)
    	{
    		if (tot)
    		f[t]=f[P[tot][0]]+(sum[P[tot][0]]-sum[t]-size[t]*(dp[t]-dp[P[tot][0]]));
    		else
    		f[t]=f[Fa]+1;
    		f[t]=min(f[t],f[Fa]+(sum[Fa]-sum[t]-size[t]*(dp[t]-dp[Fa]))+(!D[Fa]));
    	}
    	
    	if (!nx[t])
    	return;
    	
    	++tot;P[tot][0]=t;P[tot][1]=d[t];
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=nx[t])
    	Dfs(t,a[i][0]);
    	if (tot && P[tot][0]==t) --tot;
    	
    	if (nx[t])
    	{
    		++tot;P[tot][0]=t;P[tot][1]=D[t];
    		Dfs(t,nx[t]);
    		if (tot && P[tot][0]==t) --tot;
    	}
    }
    
    int main()
    {
    	#ifdef file
    	freopen("uoj84.in","r",stdin);
    	#endif
    //	freopen("b.out","w",stdout);
    	
    	scanf("%d",&n);j=k=0;
    	fo(i,1,n+n)
    	{
    		ch=getchar();
    		while (ch!='(' && ch!=')') ch=getchar();
    		
    		if (ch=='(') fa[++k]=p[j],p[++j]=k;
    		else --j;
    	}
    	fo(i,2,n) New(fa[i],i);
    	
    	dfs(1);
    	Dfs(0,1);
    	
    	ans=9223372036854775807ll;
    	fo(i,1,n) if (!nx[i]) ans=min(ans,f[i]);
    	printf("%lld
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    Luogu P4316 绿豆蛙的归宿 题解报告
    Luogu P1850 换教室(NOIP 2016) 题解报告
    Rainbow的信号 题解报告
    $CH5105 Cookies$ 线性$DP+$贪心
    算法竞赛 $0×50$ 动态规划 (+一本通
    $CH5104 I-country$ 线性$DP$
    洛谷$2014$ 选课 背包类树形$DP$
    $SP703 Mobile Service DP$
    $POJ1015 Jury Compromise Dp$/背包
    $POJ1742 Coins$ 多重背包+贪心
  • 原文地址:https://www.cnblogs.com/gmh77/p/13225627.html
Copyright © 2011-2022 走看看