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
}