2018 BUPT Winter Training #3 Div.2

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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值