A - The order of a Tree
根据二叉搜索树的性质,我们知道
key[Lchild[r]]≤key[r]≤key[Rchild[r]]
,所以LDR遍历插入一定是同结构的最小字典序二叉搜索树
指针版:
#include <iostream>
#include <cstdlib>
using namespace std;
struct node;
typedef node* T;
struct node{
int val;
T l,r;
};
T tree,tem,r;
int cnt=0;
void pre(T root){
if(root==NULL)return ;
cout<<(cnt++?" ":"")<<root->val;
pre(root->l);
pre(root->r);
}
int main(){
ios::sync_with_stdio(false);
tree=nullptr;
int n,num,_l=0,_r=0;
cin>>n;
for(int i=0;i<n;i++){
cin>>num;
r=tem=tree;
while(tem!=nullptr){
r=tem;
_l=_r=0;
if(tem->val>num)tem=tem->l,_l=1;
else tem=tem->r,_r=1;
}
tem=(T)malloc(sizeof(node));
tem->val=num;
tem->l=tem->r=nullptr;
if (_r)r->r=tem;
else if (_l)r->l=tem;
else tree=tem;
}
pre(tree);
cout<<endl;
system("pause");
}
数组(离散化)版:
#include <cstdio>
#include <cstring>
#define Fi0(_x) memset((_x),0,sizeof((_x)))
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
struct node{
int v,l,r;
}tree[100005];
int mal;
inline int readi(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void insert(int r,int val){
if(mal!=1){
for(;;){
if(val<tree[r].v){
if(tree[r].l)r=tree[r].l;
else {
tree[r].l=mal;
break;
}
}else{
if(tree[r].r)r=tree[r].r;
else {
tree[r].r=mal;
break;
}
}
}
}
tree[mal].v=val;
tree[mal].l=tree[mal].r=0;
mal++;
}
int cnt;
void preprt(int r){
printf("%s%d",cnt++?" ":"",tree[r].v);
if(tree[r].l)preprt(tree[r].l);
if(tree[r].r)preprt(tree[r].r);
}
int main(){
int n,k;
while(~scanf("%d",&n)){
mal=1;cnt=0;
memset(tree,0,sizeof(tree));
F(i,n)insert(1,readi());
if(mal!=1)preprt(1);
puts("");
}
}
B - Binary Tree Traversals
先序遍历和中序遍历可以确定根的位置,以根的位置划分,一定可以构建唯一结构的二叉搜索树,以此输出后序遍历即可。
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
struct node;
typedef node* T;
struct node {
int val;
T l,r;
};
T tree;
int cnt=0,a1[1005],a2[1005];
T set(T &r,int* x1,int* x2,int l) {
if (l<=0)return NULL;
r=(T)malloc(sizeof(node));
r->val=x1[0];
int p=0;while (x2[p]!=x1[0])p++;
r->l=set(r->l,x1+1,x2,p);
r->r=set(r->r,x1+p+1,x2+p+1,l-p-1);
return r;
}
void post(T root) {
if (root==NULL)return;
post(root->l);
post(root->r);
cout<<(cnt++?" ":"")<<root->val;
}
int main() {
ios::sync_with_stdio(false);
int n;
while(cin>>n){
cnt=0;
for (int i=0;i<n;i++)cin>>a1[i];
for (int i=0;i<n;i++)cin>>a2[i];
set(tree,a1,a2,n);
post(tree);
cout<<endl;
}
}
C - Cow Marathon
反证法可证,任意一点dfs的最远距离另一端一定是树的直径的一个端点。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
using namespace std;
struct node;
typedef node* T;
struct node {
int link[4],edge[4];
}tree[40005];
int dic[200],point,ans=0;
int dfs(int id,int from,int anss) {
int flag=1;
for (int i=0;i<4;i++) {
if (tree[id].link[i]&&tree[id].link[i]!=from){
flag=0;
dfs(tree[id].link[i],id,anss+tree[id].edge[i]);
}
}
if(flag&&ans<anss)ans=anss,point=id;
}
int main() {
ios::sync_with_stdio(false);
memset(tree,0,sizeof(tree));
dic['N']=0;dic['W']=1;dic['E']=2;dic['S']=3;
int n,m,from,to,v;string way;
cin>>n>>m;
for (int i=0;i<m;i++) {
cin>>from>>to>>v>>way;
tree[from].link[dic[way[0]]]=to;
tree[from].edge[dic[way[0]]]=
tree[to].edge[3-dic[way[0]]]=v;
tree[to].link[3-dic[way[0]]]=from;
}
for (int i=0;i<4;i++)if (tree[1].link[i])dfs(tree[1].link[i],1,tree[1].edge[i]);
ans=0;
for (int i=0;i<4;i++)if (tree[point].link[i])dfs(tree[point].link[i],point,tree[point].edge[i]);
cout<<ans;
}
D - Out of Hay
求最小生成树的最大边。
#include <iostream>
#include <vector>
#include <utility>
#include <queue>
#include <cstring>
#define PB push_back
#define MP make_pair
#define sec second
#define fir first
using namespace std;
typedef long long ll;
typedef pair<int,ll> pil;
vector<pil> V[2005];
struct cmp {
bool operator()(const pil x,const pil y)const {
return x.sec>y.sec;
}
};
priority_queue<pil,vector<pil>,cmp > Q;
ll dist[2005],in[2005]={false},ans=0;
int main() {
ios::sync_with_stdio(false);
memset(dist,0x3f,sizeof(dist));
int n,m,a,b,e;
cin>>n>>m;
for (int i=0;i<m;i++) {
cin>>a>>b>>e;
V[a].PB(MP(b,e));
V[b].PB(MP(a,e));
}
in[1]=true;
for(vector<pil>::iterator c=V[1].begin();c!=V[1].end();++c){
if (c->sec<dist[c->fir])
dist[c->fir]=c->sec,Q.push(*c);
}
pil t;
while (!Q.empty()) {
t=Q.top();
Q.pop();
if (in[t.fir])continue;
if (ans<t.sec)ans=t.sec;
in[t.fir]=true;
for(vector<pil>::iterator c=V[t.fir].begin();c!=V[t.fir].end();++c){
if (!in[c->fir]&&c->sec<dist[c->fir]) {
dist[c->fir]=c->sec;
Q.push(*c);
}
}
}
cout<<ans<<endl;
system("pause");
}
E - 公路修建问题
这道题真的是血泪!首先数据就很有问题。
思考一下,这个决策是非贪心的,所以只能够用枚举,所以我们采用一个更加优雅的方式:套个二分搜索*logn时间。
自己写的还没过…就先不贴上来了。(本地对了OJ提示错误,就说明OJ有问题,哼。)
F - Kuglarz
考虑到只有询问到点才能猜出下面到底有没有球,于是自底向上会形成一个代价树,我们要求的就是这个树的最小代价…so,最小代价就出来了
#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
using namespace std;
#define MO 1061109567
#define Fi0(_x) memset((_x),0,sizeof((_x)))
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
#define MP make_pair
#define sec second
#define fir first
int c[2005][2005]={0},dist[2005];
inline int readi(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
typedef pair<int,int> pii;
priority_queue<pii,vector<pii>,greater<pii> > q;
bool vis[2005]={0};
int main(){
int n;long long ans=0LL;
scanf("%d",&n);
memset(dist,0x3f,sizeof(dist));dist[0]=0;
FF(i,1,n)FF(j,i,n)c[i-1][j]=c[j][i-1]=readi();
q.push(MP(0,0));
pii tem;
while(!q.empty()){
tem=q.top();q.pop();
if(vis[tem.sec])continue;
vis[tem.sec]=1;
ans+=tem.fir;
FF(i,1,n){
if(c[tem.sec][i]==0)continue;
if(c[tem.sec][i]<dist[i]){
dist[i]=c[tem.sec][i];
q.push(MP(dist[i],i));
}
}
}
printf("%lld",ans);
return 0;
}
G - Cheering up the Cows
最小生成树裸题,不讲了…
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
#define PB push_back
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define LLMAX 0x7fffffffffffffffL
#define all(x) x.begin(),x.end()
using namespace std;
typedef long long ll;
inline int readi(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
struct edge{
int u,v,val;
edge(int _u=0,int _v=0,int _val=0){u=_u;v=_v;val=_val;}
bool operator<(const edge &x)const{return val<x.val;}
};
vector<edge> E;
int c[10005],pre[10005];
ll ans=LLMAX;
int find(int x){
int r=x,tem;
while(pre[r]!=r)r=pre[r];
while(x!=r){tem=pre[x];pre[x]=r;x=tem;}
return r;
}
bool uni(int x,int y){
if((x=find(x))!=(y=find(y))){
pre[x]=y;
return true;
}
return false;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
FF(i,1,n){
c[i]=readi();
if(ans>c[i])ans=c[i];
pre[i]=i;
}
int u,v;
E.clear();
F(i,m){
u=readi();v=readi();
E.PB(edge(u,v,(readi()<<1)+c[u]+c[v]));
}
sort(all(E));
F(i,m)if(uni(E[i].u,E[i].v))a```````````````````
s+=E[i].val;
printf("%lld\n",ans);
}
}
H - Pasture Walking
LCA裸题,不讲了..
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define PB push_back
#define TRV(_i,_V) for(int _i=(_V).size()-1;_i+1;_i--)
#define Fi0(_x) memset((_x),0,sizeof((_x)))
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
using namespace std;
vector<short> ade[1005];
int dist[1005];
short fa[1005][20],E[1005][1005],depth[1005];
bool vis[1005];
queue<int> q;
int LCA(int x,int y){
int t;
if(depth[x]>depth[y]){t=x;x=y;y=t;}
FS(i,13,0)if(depth[fa[y][i]]>=depth[x])y=fa[y][i];
FS(i,13,0)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return x==y?x:fa[x][0];
}
int main(){
int N,Q,u,v,e;
while(~scanf("%d%d",&N,&Q)){
FF(i,1,N)ade[i].clear();Fi0(vis);
F(i,N-1){
scanf("%d%d%d",&u,&v,&e);
E[u][v]=E[v][u]=e;
ade[u].PB(v);ade[v].PB(u);
}
q.push(1);dist[1]=0;depth[1]=1;
while(!q.empty()){
u=q.front();q.pop();
if(vis[u])continue;
vis[u]=1;
TRV(i,ade[u])if(!vis[ade[u][i]]){
fa[ade[u][i]][0]=u;
dist[ade[u][i]]=dist[u]+E[ade[u][i]][u];
depth[ade[u][i]]=depth[u]+1;
q.push(ade[u][i]);
}
}
FF(dep,1,13)FF(i,1,N)fa[i][dep]=fa[fa[i][dep-1]][dep-1];
F(q,Q){
scanf("%d%d",&u,&v);
printf("%d\n",dist[u]+dist[v]-(dist[LCA(u,v)]<<1));
}
}
}
I - Meet 紧急集合
求三点间总的距离和,那么我们先求出LCA,通过LCA之间的加加减减就可以凑出这个距离了。
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define PB push_back
#define TRV(_i,_V) for(int _i=(_V).size()-1;_i+1;_i--)
#define Fi0(_x) memset((_x),0,sizeof((_x)))
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
using namespace std;
vector<int> ade[500005];
int fa[500005][20];
short depth[500005];
bool vis[500005]={0};
queue<int> q;
int LCA(int x,int y){
int t;
if(depth[x]>depth[y]){t=x;x=y;y=t;}
FS(i,19,0)if(depth[fa[y][i]]>=depth[x])y=fa[y][i];
FS(i,19,0)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return x==y?x:fa[x][0];
}
int main(){
int N,Q,u,v,c,r,r1,r2,r3;
scanf("%d%d",&N,&Q);
F(i,N-1){
scanf("%d%d",&u,&v);
ade[u].PB(v);ade[v].PB(u);
}
q.push(1);depth[1]=1;
while(!q.empty()){
u=q.front();q.pop();
if(vis[u])continue;
vis[u]=1;
TRV(i,ade[u])if(!vis[ade[u][i]]){
fa[ade[u][i]][0]=u;
depth[ade[u][i]]=depth[u]+1;
q.push(ade[u][i]);
}
}
FF(dep,1,19)FF(i,1,N)fa[i][dep]=fa[fa[i][dep-1]][dep-1];
F(q,Q){
scanf("%d%d%d",&u,&v,&c);
r1=LCA(u,v);r2=LCA(u,c);r3=LCA(v,c);
if(r1==r2)r=r3;else if(r2==r3)r=r1;else r=r2;
printf("%d %d\n",r,depth[u]+depth[v]+depth[c]+depth[r]*3-(depth[LCA(u,r)]+depth[LCA(v,r)]+depth[LCA(c,r)])*2);
}
}
J - Misha, Grisha and Underground
求三点间最大公共距离,先求出LCA,我们就可以通过点之间的加加减减求出这个值。
#include <cstdio>
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
const int N=100000;
inline int readi(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int head[N+5]={0},mal=1;
int fa[N+5][18]={0},depth[N+5];
struct edge{
int from,to,next;
}e[(N<<1)+5];
void addedge(int u,int v){
e[mal].from=u;
e[mal].to=v;
e[mal].next=head[u];
head[u]=mal++;
}
void dfs(int u){
int to;
for(int i=head[u];i;i=e[i].next){
if((to=e[i].to)==fa[u][0])continue;
depth[to]=depth[u]+1;
fa[to][0]=u;
dfs(to);
}
}
int LCA(int x,int y){
int t;
if(depth[x]<depth[y]){t=x;x=y;y=t;}
for(int i=17;i>=0;i--){
if(depth[fa[x][i]]>=depth[y])x=fa[x][i];
}
if(x!=y){
for(int i=17;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];y=fa[y][i];
}
}
x=fa[x][0];
}
return x;
}
inline void init(){
for(int i=1;i<=17;i++)FF(j,1,N)fa[j][i]=fa[fa[j][i-1]][i-1];
}
int main(){
int N,Q,p,u,v,l1,l2,l3,x,y,z,ans,anss;
N=readi();Q=readi();
FF(i,2,N){addedge(p=readi(),i);addedge(i,p);}
depth[1]=1;
dfs(1);
init();
F(q,Q){
p=readi();u=readi();v=readi();
x=LCA(p,u);y=LCA(u,v);z=LCA(p,v);
l1=depth[p]+depth[u]-(depth[x]<<1);
l2=depth[v]+depth[u]-(depth[y]<<1);
l3=depth[p]+depth[v]-(depth[z]<<1);
ans=(l1+l2-l3)>>1;
if(ans<(anss=((l2+l3-l1)>>1)))ans=anss;
if(ans<(anss=((l1+l3-l2)>>1)))ans=anss;
printf("%d\n",ans+1);
}
}