[倍增 堆] BZOJ 4458 GTY的OJ

题解:JudgeOnline/upload/201604/Solution-4458.rar By jinlifu1999


超级钢琴...都已经成经典了

本来想打树链剖分和ST表的,后来看题解发现倍增更好打,膜打树链的Evan

题目后跟个题解链接是SMG


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<ll,int> abcd;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x){
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(ll &x){
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

int n,m,L,R,M;
ll ans;
int depth[500005];
ll s[500005];
int fat[500005][25];
abcd st[500005][25];

inline void build_fat(){
	for (int k=1;k<=20;k++)
		for (int i=1;i<=n;i++)
			fat[i][k]=fat[fat[i][k-1]][k-1];
}

inline int Fat(int u,int d){
	for (int k=20;k>=0;k--)
		if ((d>>k)&1)
			u=fat[u][k];
	return u;
}

inline void build_st(){
	for (int i=0;i<=n;i++)
		st[i][0]=abcd(s[i],i);
	for (int k=1;k<=20;k++)
		for (int i=0;i<=n;i++)
			st[i][k]=min(st[i][k-1],st[fat[i][k-1]][k-1]);
}

inline abcd Query(int u,int d){
	abcd ret(1LL<<60,0);
	for (int k=20;k>=0;k--)
		if ((d>>k)&1)
			ret=min(ret,st[u][k]),u=fat[u][k];
	return ret;
}

struct node{
	int u,l,r,m;
	ll val;
	node () { }
	node (int u,int l,int r):u(u),l(l),r(r) { }
	void calc(){
		int f=Fat(u,l+1);
		abcd ret=Query(f,r-l);
		val=s[u]-ret.first;
		m=depth[u]-depth[ret.second];
	}
	bool operator < (const node &B) const{
		return val<B.val;
	}
};

priority_queue<node> Q;

int main()
{
	int l,r;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n);
	for (int i=1;i<=n;i++)
		read(fat[i][0]);
	for (int i=1;i<=n;i++)
		read(s[i]);
	read(M); read(L); read(R); 
	for (int i=1;i<=n;i++)
		s[i]+=s[fat[i][0]],depth[i]=depth[fat[i][0]]+1;
	build_fat();
	build_st();
	node tmp;
	for (int i=1;i<=n;i++)
	{
		if (L>depth[i]) continue;
		l=L-1; r=min(R,depth[i]);
		if (l<r)
		{
			tmp=node(i,l,r);
			tmp.calc();
			Q.push(tmp);
		}
	}
	for (int i=1;i<=M;i++)
	{
    	if (Q.empty()) return printf("-01\n"),0;
		tmp=Q.top(); Q.pop();
		ans+=tmp.val;
		int m=tmp.m,l=tmp.l,r=tmp.r,u=tmp.u;
		if (l<m-1)
		{
			tmp=node(u,l,m-1);
			tmp.calc();
			Q.push(tmp);
		}
		if (m<r)
		{
			tmp=node(u,m,r);
			tmp.calc();
			Q.push(tmp);
		}
	}
	printf("%lld\n",ans);
	return 0;
}


你可能感兴趣的:([倍增 堆] BZOJ 4458 GTY的OJ)