赛时lca挂90pts,求调
查看原帖
赛时lca挂90pts,求调
767588
_fwTransform_楼主2024/7/14 22:50

RT,写的挺急马蜂炸裂,但一定是赛时码 注释辅助理解不算赛时码对8()

#include <bits/stdc++.h>
#define Arknights return
#define AK 0
#define IOI ;
#define ll long long
#define ld long double
#define ull unsigned ll
#define lll __int128
#define pii pair<int,int>
#define pip pair<int,pii>
#define ppp pair<pii,pii>
#define deb cerr<<"Arknights AK IOI\n"
#define tostring(a) #a
#define cono(a,b) a##b
#define psa(i) (i=-~(i))
#define range(i) (-~(i))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;

inline ll read()
{
	ll s=0;int w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^'0'),ch=getchar();
	return s*w;
}
void IO()
{
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);
}
const int maxn=3e5+10;

ll w[maxn];
ll res[maxn];
int dep[maxn];
ll ans;
int num;

int lca(int x,int y)
{
//	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y])x>>=1;
	while(x!=y)x>>=1,y>>=1;
	return x;
}
ll summ(int pos,int hit)
{//暴力求 pos为根 深度为 hit 的子树和
	if(!hit)return 0;
	if(pos>=num)return 0;
	return w[pos]+summ(pos<<1,hit-1)+summ(pos<<1|1,hit-1);
}
int main()
{
	int n=read(),m=read();
	num=1<<n;//点的多少
	for(int i=1;i<num;++i)
	{
		res[i]=w[i]=read();
		dep[i]=dep[i>>1]+1;
	}
	num>>=1;
	for(int i=num-1;i;--i)
	{
		res[i]+=res[i<<1]+res[i<<1|1];
	}
	num<<=1;
	while(m--)
	{
		int x=read(),y=read(),k=read();
		if(k+2>=2*n)//大于2倍直径绝对可行
		{
			printf("%lld\n",res[1]);
			continue;
		}
		if(dep[x]<dep[y])swap(x,y);//x更深
		int fath=lca(x,y),dis;
		if(fath==y)dis=dep[x]-dep[y];//x,y在一条链上
		else dis=dep[x]-dep[fath]+dep[y]-dep[fath];
//		if(dis>2*k)printf("0\n");
//		printf("dis:%d\n",dis);
//		cerr<<"dis: "<<dis<<endl;
		if(dis&1)
		{//路径单数,中点两个,父子关系
			dis>>=1;
			int tmpx=x>>dis;//上跳dis/2个深度,子中点
			int tmpy=tmpx>>1;//x更深,tmpx子,tmpy父
//			cerr<<tmpx<<' '<<tmpy<<endl;
			k-=dis+1;
			if(k<0)ans=0;//k<路径中点,没有贡献点
			else if(!k)ans=w[tmpx]+w[tmpy];//恰好
			else 
			{//tmpx向下搜k,tmpy向上跳搜另一支
				ans=summ(tmpx,k)+w[tmpy];
				for(;k;--k,tmpy>>=1,tmpx>>=1,ans+=w[tmpy])
					ans+=summ(tmpx^1,k);
			}
		}
		else
		{//路径双数,一个中点
			dis>>=1;
			int tmpx=x>>dis;
			k-=dis;
			if(k<0)ans=0;
			else if(!k)ans=w[tmpx];
			else
			{
				++k;//除自己向下一个深度
				ans=summ(tmpx,k);
				for(--k,ans+=w[(tmpx>>1)];k;--k,tmpx>>=1,ans+=w[(tmpx>>1)])
					ans+=summ(tmpx^1,k);
			}
		}
		printf("%lld\n",ans);
	}
	Arknights AK IOI
}
2024/7/14 22:50
加载中...