A题
给出两棵编号1-n的树A和B,A、B树上每个节点均有一个权值,给出k个关键点的编号x1…xn,问有多少种方案使得去掉恰好一个关键点使得剩余关键点在树A上LCA的权值大于树B上LCA的权值。
一道基础的LCA的模板题,简单树剖求LCA但因为大家只知道2个节点的最近公共祖先,不清楚多个节点的最小公共祖先是什么,所以一直在尝试理解这个最小公共祖先是什么,所以也wa和t了好几发(虽然都是我干的,对不起队友们)后面让大佬队友理解到了最小公共祖先,就很快过了。
LCA的模板比赛的时候忘记了,现场重新写了一遍,所以耗了很多时间。
#include<bits/stdc++.h>
using namespace std;
int n,m,num,numb,head[100005],root,dep[100005],fa[100005][22],ja,jb,mi=100005,ma=-1;
int k[100005];
int qa[100005],qb[100005],headb[100005],depb[100005],fab[100005][22],xa[100005],xb[100005];
long long int ans;
bool flag;
struct op
{
int next,to;
};
op edge[2500000];
op edgeb[2500000];
void add(int from,int to)
{
edge[num].next=head[from];
edge[num].to=to;
head[from]=num++;
}
void addb(int from,int to)
{
edgeb[numb].next=headb[from];
edgeb[numb].to=to;
headb[from]=numb++;
}
void dfs(int x,int f)
{
dep[x]=dep[f]+1;
fa[x][0]=f;
for (int i=head[x]; i!=-1; i=edge[i].next)
{
int e=edge[i].to;
if (e==f)
continue;
dfs(e,x);
}
}
void dfsb(int x,int f)
{
depb[x]=depb[f]+1;
fab[x][0]=f;
for (int i=headb[x]; i!=-1; i=edgeb[i].next)
{
int e=edgeb[i].to;
if (e==f)
continue;
dfsb(e,x);
}
}
int lca(int x,int y)
{
if (dep[y]>dep[x])
swap(x,y);
for (int i=20; i>=0; i--)
{
if (dep[fa[x][i]]>=dep[y])
x=fa[x][i];
}
if (x==y)
return x;
for (int i=20; i>=0; i--)
{
if (fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
int lcb(int x,int y)
{
if (depb[y]>depb[x])
swap(x,y);
for (int i=20; i>=0; i--)
{
if (depb[fab[x][i]]>=depb[y])
x=fab[x][i];
}
if (x==y)
return x;
for (int i=20; i>=0; i--)
{
if (fab[x][i]!=fab[y][i])
{
x=fab[x][i];
y=fab[y][i];
}
}
return fab[x][0];
}
int main()
{
memset(head,-1,sizeof(head));
memset(headb,-1,sizeof(headb));
scanf("%d%d",&n,&m);
root=1;
for (int i=1;i<=m;i++)
{
scanf("%d",&k[i]);
}
sort(k+1,k+1+m);
for (int i=1;i<=n;i++)
scanf("%d",&qa[i]);
for (int i=2; i<=n; i++ )
{
scanf("%d",&xa[i]);
add(xa[i],i);
add(i,xa[i]);
}
dfs(root,0);
// cout<<"wdsd";
for (int i=1; i<=20; i++ )
for (int j=1; j<=n; j++ )
fa[j][i]=fa[fa[j][i-1]][i-1];
//
for (int i=1;i<=n;i++)
scanf("%d",&qb[i]);
for (int i=2; i<=n; i++ )
{
scanf("%d",&xb[i]);
addb(xb[i],i);
addb(i,xb[i]);
}
dfsb(root,0);
// cout<<"wdsd";
for (int i=1; i<=20; i++ )
for (int j=1; j<=n; j++ )
fab[j][i]=fab[fab[j][i-1]][i-1];
for (int i=1;i<=m;i++)
{
if (i==1)
{
ja=lca(k[2],k[m]);
jb=lcb(k[2],k[m]);
if (ja==k[i])
ja=xa[k[i]];
if (jb==k[i])
jb=xb[k[i]];
if (qa[ja]>qb[jb])
ans++;
continue;
}
if (i==m)
{
ja=lca(k[1],k[m-1]);
jb=lcb(k[1],k[m-1]);
if (ja==k[i])
ja=xa[k[i]];
if (jb==k[i])
jb=xb[k[i]];
if (qa[ja]>qb[jb])
ans++;
continue;
}
ja=lca(k[1],k[m]);
jb=lcb(k[1],k[m]);
if (ja==k[i])
ja=xa[k[i]];
if (jb==k[i])
jb=xb[k[i]];
if (qa[ja]>qb[jb])
ans++;
}
cout<<ans;
return 0;
}
C题
签到题了,题意是给定n个字符串,求一个将他们拼接起来的方案,使得结果的字典序最小。
很简单,就是对n个字符串排序,保障小的条件是a+b<b+a,但不知道最开始哪里出错了,导致wa了一发,然后大家重新写了一下,就过了,很离谱。
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
const int N=2e6+7;
string s[N];
inline string read(){
string s="";
char ch=getchar();
while(!(ch>='0'&&ch<='4')){
ch=getchar();
}
while(ch>='0'&&ch<='4'){
s+=ch;ch=getchar();
}
return s;
}
bool cmp(int a,int b){
return s[a]+s[b]<s[b]+s[a];
}
int main(){
int n;int q[N];
int i;
cin>>n;
for(i=0;i<n;i++)q[i]=i;
for(i=0;i<n;i++)s[i]=read();
sort(q,q+n,cmp);
for(i=0;i<n;i++){
cout<<s[q[i]];
}
cout<<endl;
}
补题时间
J题
给定一个城市有若干十字路口,右转不需要等红灯,直行、左转和掉头都需要,求起点到终点最少等几次红灯。看大佬用bfs或dij就可以过了,我们队伍坐牢3小时还是没写出来,太痛苦了。
当然也有很多大佬用spfa也可以,但我现在只会写dij了,烂透了wwww
下面是其他题解大佬的代码,我只能做到大致看懂......
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
const int N = 2e6 + 10;
const int M = N * 4;
typedef pair<int,int> PII;
bool st[M];
int n;
int tt;
int start,et;
int w[N][4];
int dist[M];
map<PII,int>id;
struct road{
int a;
int b;
}r[M];
struct edge{
int to;
int next;
int w;
}tu[M];
int h[M];
int idx;
void init(){
memset(h,-1,sizeof h);
}
void add(int u,int v,int w){//加边,从u到v,权值为w
tu[idx].to = v;
tu[idx].w = w;
tu[idx].next = h[u];
h[u] = idx ++;
}
int dij(){
memset(dist,0x3f,sizeof dist);
dist[start] = 0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,start});//距离;节点
while(heap.size()){
auto t = heap.top();
heap.pop();
int distance = t.first;
int ver = t.second;
if(st[ver]) continue;
st[ver] = true;
for(int i = h[ver];i != -1;i = tu[i].next){
int j = tu[i].to;//当前的终点
dist[j] = min(dist[j],dist[ver] + tu[i].w);
heap.push({dist[j],j});
}
}
if(dist[et] == 0x3f3f3f3f) return -1;
else return dist[et];
}
int main(){
init();
tt = 1;
scanf("%d",&n);
for(int i = 1;i <= n;i++){
for(int j = 0;j < 4;j++){
scanf("%d",&w[i][j]);
if(w[i][j]){
r[tt].a = i;
r[tt].b = w[i][j];
id[make_pair(i,w[i][j])] = tt++;
}
}
}
for(int i = 1;i < tt;i++){
bool a = 0;
for(int j = 0;j < 4;j++){
if(r[i].b && w[r[i].b][j] == r[i].a){
a = 1;
for(int k = 1;k <= 4;k++){
int h = (j + k) % 4;
if(k == 1 && w[r[i].b][h] != 0){
int t = id[{r[i].b,w[r[i].b][h]}];
add(i,t,0);
}
if(k != 1 && w[r[i].b][h] != 0){
int t = id[{r[i].b,w[r[i].b][h]}];
add(i,t,1);
}
}
}
if(a) break;
}
}
int s1,s2,e1,e2;
scanf("%d%d%d%d",&s1,&s2,&e1,&e2);
start = id[{s1,s2}];
et = id[{e1,e2}];
int ans = dij();
printf("%d",ans);
return 0;
}