7.7集训----集训模拟赛10 高考

7.7集训----集训模拟赛10 高考

A. 不知道叫什么名字 题目描述

7.7集训----集训模拟赛10 高考


7.7集训----集训模拟赛10 高考

分析

一道裸的LCA板子题,就是卡常有点难受,注释在代码里

代码 #include<bits/stdc++.h> using namespace std; const int maxn=22,maxk=1000005; int f[maxk][maxn]; int head[maxk],tot=1; struct asd{ int to,next,val; }b[maxk>>1]; inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } inline void write(int x){ if(x<0){ putchar('-'); x=-x; } if(x>9) write(x/10); putchar(x%10+'0'); } void ad(int aa,int bb,int cc){ b[tot].to=bb; b[tot].next=head[aa]; b[tot].val=cc; head[aa]=tot++; } int dep[maxk]; void dfs(int now,int fa,int da){ f[now][0]=fa; dep[now]=dep[fa]+1; for(int i=1;(1<<i)<=dep[now];i++){ f[now][i]=f[f[now][i-1]][i-1]; } for(int i=head[now];i!=-1;i=b[i].next){ int u=b[i].to; if(u==fa) continue; dfs(u,now,b[i].val); } } int get_LCA(int xx,int yy){ if(dep[xx]<dep[yy]) swap(xx,yy); int len=dep[xx]-dep[yy],k=0; while(len){ if(len&1){ xx=f[xx][k]; } len>>=1; k++; } if(xx==yy) return xx; for(int i=20;i>=0;i--){ if(f[xx][i]==f[yy][i]) continue; xx=f[xx][i]; yy=f[yy][i]; } return f[xx][0]; } int main(){ memset(head,-1,sizeof(head)); int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<n;i++){ int aa,bb; aa=read(),bb=read(); ad(aa,bb,1); ad(bb,aa,1); } dfs(m,0,0); int bef=m; for(int i=1;i<=k;i++){ int aa,bb; aa=read(),bb=read(); int gg=get_LCA(bef,aa);//上一次的位置到现在位置的花费 int tot=dep[aa]+dep[bef]-dep[gg]*2; if(tot<=bb){ write(aa);//如果小于步数,可以达到 printf(" "); bef=aa; } else {//否则 //求出要到达的节点与之前节点的最近公共祖先 int now=dep[bef]-dep[gg];//求出之前节点到公共祖先的距离 if(now>=bb){//如果当前节点到公共祖先的距离大于步数 int ans=bb; int k=0; while(ans){ if(ans&1) bef=f[bef][k]; k++; ans>>=1; } write(bef);//将之前的节点想上跳要到达的步数 printf(" "); } else {//如果当前节点到公共祖先的距离小于步数,则在另一分支 int ans=bb-now;//求出在另一分支上的步数 int zjz=dep[aa]-dep[gg];//求出要到达的节点到最近公共祖先的距离 int zjz2=zjz-ans;//距离减去步数 int k=0; while(zjz2){ if(zjz2&1) aa=f[aa][k]; k++; zjz2>>=1; } write(aa); printf(" "); bef=aa; } } } return 0; } B、虫洞 题目描述

7.7集训----集训模拟赛10 高考


7.7集训----集训模拟赛10 高考


7.7集训----集训模拟赛10 高考

分析

我们建两层点,其中\([1,n]\)代表白洞,\([n+1,n\times 2]\)代表黑洞
如果我们建边的时候,如果该边上的两个点都是黑洞或者白洞
那么在我们进行跃进的时候,只需要花费原来的价值就可以
所以我们从\(aa\)\(bb+n\),从\(aa+n\)\(bb\)分别建一条边,权值为输入的权值即可
如果两个点一个是黑洞一个是白洞,我们就按照题目中的要求建边
最后我们还要考虑在某个节点停留的情况
我们需要从\(i\)\(i+n\)建一条权值为\(0\)的边,代表在白洞停留
\(i+n\)\(i\)建一条权值为该点燃料消耗的边,代表在黑洞停留

代码 #include<bits/stdc++.h> using namespace std; const int maxn=6e5+5; typedef long long ll; struct asd{ int from,to,next; ll val; }b[maxn]; int head[maxn],tot=1; void ad(int aa,int bb,ll cc){ b[tot].from=aa; b[tot].to=bb; b[tot].val=cc; b[tot].next=head[aa]; head[aa]=tot++; } int hd[maxn]; ll zl[maxn],rl[maxn]; struct jie{ int num,tim,kk; ll jl; jie(int aa=0,ll bb=0){ num=aa,jl=bb; } bool operator < (const jie& A)const { return jl>A.jl; } }; priority_queue<jie> q; ll dis[maxn]; bool vis[maxn]; void dij(int xx){ memset(dis,0x3f,sizeof(dis)); dis[xx]=0; q.push(jie(xx,0)); while(!q.empty()){ int now=q.top().num; q.pop(); if(vis[now]) continue; vis[now]=1; for(int i=head[now];i!=-1;i=b[i].next){ int u=b[i].to; if(dis[u]>dis[now]+b[i].val){ dis[u]=dis[now]+b[i].val; q.push(jie(u,dis[u])); } } } } int main(){ memset(head,-1,sizeof(head)); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&hd[i]); } for(int i=1;i<=n;i++){ scanf("%lld",&zl[i]); } for(int i=1;i<=n;i++){ scanf("%lld",&rl[i]); } for(int i=1;i<=m;i++){ int aa,bb; ll cc; scanf("%d%d%lld",&aa,&bb,&cc); if(hd[aa]==hd[bb]){ ad(aa,bb+n,cc); ad(aa+n,bb,cc); } else { ll cz=abs(zl[aa]-zl[bb]); ad(aa+n,bb+n,cc+cz); ad(aa,bb,max(cc-cz,0ll)); } } for(int i=1;i<=n;i++){ ad(i,i+n,0ll); ad(i+n,i,rl[i]); } if(hd[1]==1) dij(n+1); else dij(1); printf("%lld\n",min(dis[n],dis[n*2])); return 0; } C、图腾计数 题目描述

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyygzf.html