求优化!我第10个点只差0.03s!
查看原帖
求优化!我第10个点只差0.03s!
413905
Nicolas192837楼主2023/12/31 17:21

原题:P2607 [ZJOI2008] 骑士
就差最后一个点了,卡了二十多次常了,最后一个点是死活过不去,现在还差0.03s,求优化

#include<bits/stdc++.h>
using namespace std;
int read()
{
    int x=0;
    char c=getchar();
    while(c<47)
    {
        c=getchar();
    }
    while(c>47)
    {
        x=x*10+c-'0';
        c=getchar();
    }
    return x;
}//快读
void wit(long long x)
{
    if(x!=0)
    {
        wit(x/10);
        putchar(x%10+'0');
    }
    return ;
}
void write(long long x,bool edl)
{
    if(x<=0)
    {
        if(x==0)
        {
            putchar('0');
        }else{
            putchar('-');
            wit(x*(-1));
        }
    }else{
        wit(x);
    }
    if(edl)
    {
        putchar('\n');
    }else{
        putchar(' ');
    }
    return ;
}//18~48行为快速输出
const int N=1e6;
int n,w,p,sp1,sp2,val[N+5];//val存点权,
bool re1[N+5][2]={false},re[N+5]={false};//用于判重
vector<int>a[N+5],tree[N+5];//a存边,tree用于后续建树
long long ans=0,dp[N+5][2],ans1,ans2;
void del(int p,int las)
{
	re[p]=true;
	for(int i=0;i<a[p].size();i++)
	{
		if(!re[a[p][i]])
		{
			del(a[p][i],p);
		}else{
			if(a[p][i]!=las)
			{
				sp1=a[p][i];
				sp2=p;
			}
		}
	}
}//del函数用于找出某个连通块的随机一条基环树环部分的边
void planttree(int p,int id)
{
	re1[p][id]=true;
	tree[p].clear();
	for(int i=0;i<a[p].size();i++)
	{
		if(!re1[a[p][i]][id])
		{
			tree[p].push_back(a[p][i]);
			planttree(a[p][i],id);
		}
	}
}//建树
void f1(int p)
{
	long long a1=val[p],a2=0;
	for(int i=0;i<tree[p].size();i++)
	{
		f1(tree[p][i]);
		a1+=dp[tree[p][i]][0];
		a2+=max(dp[tree[p][i]][0],dp[tree[p][i]][1]);
	}
	dp[p][1]=a1;
	dp[p][0]=a2;
	return ;
}//dp,用递归实现向上转移
long long f(int p)
{
	long long h=0;
	for(int i=0;i<tree[p].size();i++)
	{
		f1(tree[p][i]);
		h+=max(dp[tree[p][i]][0],dp[tree[p][i]][1]);
	}
	return h;
}//假设根节点不取,对每个树求答案
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
	{
		w=read();
		p=read();
		a[i].push_back(p);
		a[p].push_back(i);
		val[i]=w;
	}//建图
	for(int i=1;i<=n;i++)
	{
		if(re[i])
		{
			continue;
		}
		del(i,-1);//割边,对某个连通块建树
		planttree(sp1,0);//对于割掉的那个边,取左端点为树的根节点建树
		ans1=f(sp1);//求左端点不取的时候该连通块的最大贡献
		planttree(sp2,1);
		ans2=f(sp2);//同理处理右端点
		ans+=max(ans1,ans2);
	}
	write(ans,true);//输出答案
    return 0;
}
2023/12/31 17:21
加载中...