社区讨论
求一组hack或指出我思路中的错误
P9481[NOI2023] 贸易参与者 3已保存回复 7
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 7 条
- 当前快照
- 1 份
- 快照标识符
- @lo205tky
- 此快照首次捕获于
- 2023/10/23 05:50 2 年前
- 此快照最后确认于
- 2023/11/03 06:14 2 年前
思路:建立反向图,之后统计每个节点答案的时候,每次暴力取出这个节点的所有祖先和所有后代并在反向图上进行一个的跑
但交上去只有分,只过了#9,#12,#16,#17,题目给的样例应输出,实际输出,不知道是我的思路的问题还是代码的问题qwq
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#include<numeric>
#include<map>
using namespace std;
const int N=1919810,mod=998244353;
const long long INF=1e18;
typedef long long ll;
typedef pair<ll,ll> PII;
ll n,m,k,s;
ll a[N];
ll h[N],e[N],ne[N],w[N],idx;
ll sz[N],caiguang[N];
bool tf[N],st[N];
ll d[N];
ll mi[50];
vector<int> son[N];
vector<int> nb;
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void xhytom(ll x){
if(x*2+1<=n){
// cout<<a[x*2]<<" "<<a[x*2+1]<<endl;
sz[x]=(a[x*2]*caiguang[x*2]%mod+a[x*2+1]*caiguang[x*2+1]%mod)%mod;
sz[x]=(sz[x]+sz[x*2])%mod;
sz[x]=(sz[x]+sz[x*2+1])%mod;
}
}
void rst(){
for(int i=0;i<nb.size();i++){
int pxa=nb[i];
tf[pxa]=0;
}
}
void dijkstra(ll x){
priority_queue<PII,vector<PII>,greater<PII> > q;
q.push({0,x});
for(int i=0;i<nb.size();i++){
d[nb[i]]=1e18;
tf[nb[i]]=0;
}
d[x]=0;
tf[x]=0;
while(q.size()){
ll t=q.top().second;
q.pop();
if(tf[t]) continue;
tf[t]=1;
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(!st[j]) continue;//如果碰到没有标记的点,则不扩展
if(d[j]>d[t]+w[i]){
d[j]=d[t]+w[i];
if(!tf[j]) q.push({d[j],j});
}
}
}
}
ll gao(int x){
nb.clear();
for(int i=0;i<son[x].size();i++){//取出x子树里面的所有点并标记
st[son[x][i]]=1;
nb.push_back(son[x][i]);
d[son[x][i]]=1e18;
}
nb.push_back(x);
st[x]=1;
d[x]=0;
ll nmsl=x/2;
while(nmsl){//取出x的所有祖先
st[nmsl]=1;
nb.push_back(nmsl);
d[nmsl]=1e18;
nmsl/=2;
}
ll ans=sz[x]%mod;
rst();
dijkstra(x);//跑最短路
nmsl=x;
while(nmsl>1){//统计答案
if(d[nmsl/2]>INF/2){
nmsl/=2;
continue;
}
ans+=d[nmsl/2]%mod*caiguang[nmsl^1]%mod;
ans%=mod;
ans+=d[nmsl/2]%mod;
ans%=mod;
ans+=(sz[nmsl^1]+a[nmsl^1]*caiguang[nmsl^1]%mod)%mod;
ans%=mod;
nmsl/=2;
}
for(int i=0;i<nb.size();i++){//清除标记
int jcjj=nb[i];
tf[jcjj]=0;
st[jcjj]=0;
}
//cout<<x<<" "<<ans<<endl;
return ans;
}
int main(){
for(int i=1;i<=25;i++) mi[i]=(1<<i)-1;
cin>>n>>m;
for(int i=0;i<n;i++){//预处理子树大小
for(int j=(1<<i);j<(1<<i+1);j++) caiguang[j]=mi[n-i];
}
n=(1<<n)-1;
// cout<<n<<endl;
memset(h,-1,sizeof h);
for(int i=2;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=2;i<=n;i++){
add(i/2,i,a[i]);//建树边(反向)
}
for(int i=n;i>=1;i--){
xhytom(i);//预处理每个节点的所有儿子只走树边到他的距离之和
}
for(int i=n;i>=1;i--){
int nmsl=i;
while(nmsl){
son[nmsl].push_back(i);//统计每个节点的所有儿子
nmsl/=2;
}
}
ll ans=0;
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(b,a,c);//建二类边(反向)
}
for(int i=n;i>=1;i--){
ans+=gao(i);//处理每个节点
ans%=mod;
//cout<<ans<<endl;
}
cout<<ans<<endl;
}
回复
共 7 条回复,欢迎继续交流。
正在加载回复...