试题编号: 201912-4
试题名称: 区块链
时间限制: 10.0s
内存限制: 512.0MB
思路from网上:按照时间顺序依次处理每个节点接收链和产生块。详见代码注释
小技巧:每个节点的接收链在传递的时候可以更新,因此接收链实际上可以是一条。
#include<iostream>
#include<map>
#include<unordered_map>
#include<array>
#include<vector>
using namespace std;
const int N=505;
map<int,unordered_map<int,array<vector<int>,2>>> act; //act[t][v][0]表示在t时刻,节点v的接收链; act[t][v][0]表示在t时刻,节点v的更新块链
vector<int> graph[N]; //存储图
vector<int> res[N]; //存储每个节点的主链
int n,m,t;
bool can_rec(vector<int>& rec,vector<int>& v) //判断rec能否更新主链v
{
return v.size()==rec.size()?v.back()>rec.back():v.size()<rec.size();
}
void spread(int v,int time) //节点v向相邻节点传播主链
{
for(int rec_v:graph[v])
{
auto &chain=act[time][rec_v][0];
if(can_rec(res[v],chain)) chain=res[v];
}
}
void query(int v,int time) //查询节点v在time时刻的主链,查询时才执行所有更新处理
{
for(auto &action:act)
{
int cur_t=action.first;
if(cur_t>time) break; //只处理到当前查询时刻
for(auto &temp:action.second)
{
int cur_v=temp.first;
auto &rec=temp.second[0],&add=temp.second[1]; //分别表示接收链和产生块
bool flag=false;
if(can_rec(rec,res[cur_v]))
{
flag=true;
res[cur_v]=rec;
}
if(!add.empty()) flag=true;
for(auto x:add) res[cur_v].push_back(x);
if(flag) spread(cur_v,cur_t+t); //只有更新才向相邻节点传递,就是这里写成了time+t,woc真是要命
}
}
act.erase(act.begin(),act.upper_bound(time)); //将time以前的操作删除,就是这里time写成了t,要疯了!
cout<<res[v].size();
for(auto ver:res[v]) cout<<" "<<ver;
cout<<endl;
}
int main()
{
cin>>n>>m;
for(int i=0,a,b;i<m;i++)
{
cin>>a>>b;
graph[a].push_back(b);
graph[b].push_back(a);
}
for(int i=1;i<=n;i++) res[i].push_back(0);
int k;
cin>>t>>k;
for(int i=0,a,b,c;i<k;i++)
{
cin>>a>>b;
if(cin.get()=='\n'||cin.eof()) query(a,b); //这里是一个小技巧,判断输入的数字是2个还是3个
else
{
cin>>c;
act[b][a][1].push_back(c);
}
}
}
需要注意的是:
时间参数的选择,写的时候就要想清楚!!!45行和48行