NOIP2013提高组Day1

来源:互联网 发布:商品sku数据库设计 编辑:程序博客网 时间:2024/06/05 14:03

NOIP2013Day1

一、转圈游戏
按照题意每个人往后m个,那就是(10^k*m+x)%n,然后用快速幂就可以了

二、火柴排队
看起来很像鬼脚图,但是有点不一样,鬼脚图的上一层是固定的,但这里两层都可以动
注意到交换对于交换上面还是交换下面效果都是一样的,那么直交换下面就可以了
这样和鬼脚图就一模一样了,排序一下,重新定义一下就行了

三、货车运输
我一档档写了过来
对于30分,和七夕是一样的,只要枚举每条边作为最小的那个限重,然后判连通,不断更新即可
对于60分,修改一下上面的,对于每一个询问,二分限重来求所需的限重。限重满足线形,越小越容易实现
对于100分,是最大生成树+倍增+LCA。注意到要使每一条路径都最长,那么短的路径就可以舍去了
用倍增和LCA求两点在树上的路径上的最小权值即可
注意这可能是森林而不是一个完整的树。我把每棵树都标上了颜色来区分。如果两点的颜色不同
那么他们所在的子树也不同,就无法连通,直接输出-1即可

Code:

#include<cstdio>#include<cstring>#include<vector>#include<algorithm>using namespace std;int n,m,q;struct node{int x,y,z;}G[50005];bool cmp(node x,node y){return x.z>y.z;}struct node1{int to,v;};vector<node1>edge[10005];struct Tree1{//造出最大生成树    int fa[10005];    int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);}    void solve(){        for(int i=1;i<=n;i++)fa[i]=i;        sort(G+1,G+1+m,cmp);        for(int i=1;i<=m;i++){            int x=Find(G[i].x),y=Find(G[i].y);            if(x==y)continue;            edge[G[i].x].push_back((node1){G[i].y,G[i].z});            edge[G[i].y].push_back((node1){G[i].x,G[i].z});            fa[x]=y;        }    }}Tree;int fa[17][10005],dep[10005],dis[17][10005],co[10005],col;struct Init1{//预处理倍增的东西    bool Q[10005];    void f(int x,int fa1){        dep[x]=dep[fa1]+1;fa[0][x]=fa1;Q[x]=1;co[x]=col;        for(int i=0;i<(int)edge[x].size();i++){            int y=edge[x][i].to,v=edge[x][i].v;            if(fa1==y)continue;            dis[0][y]=v;            f(y,x);        }    }    void Init(){//倍增        for(int j=1;j<17;j++)            for(int i=1;i<=n;i++){                fa[j][i]=fa[j-1][fa[j-1][i]];                dis[j][i]=min(dis[j-1][i],dis[j-1][fa[j-1][i]]);            }    }    void solve(){        col=1;        for(int i=1;i<=n;i++)if(Q[i]==0)f(i,0),col++;        Init();    }}Init;int LCA(int x,int y){//LCA    if(dep[x]>dep[y])swap(x,y);    int step=dep[y]-dep[x];    for(int i=0;i<17;i++)        if(step&(1<<i))y=fa[i][y];    if(x==y)return x;    for(int i=16;i>=0;i--)        if(fa[i][x]!=fa[i][y])            x=fa[i][x],y=fa[i][y];    return fa[0][x];}int work(int x,int y){//跳着向上    int step=dep[x]-dep[y],mn=1e9;    for(int i=16;i>=0;i--)        if(step&(1<<i))            mn=min(mn,dis[i][x]),x=fa[i][x];    return mn;}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)scanf("%d%d%d",&G[i].x,&G[i].y,&G[i].z);    Tree.solve();//建树    Init.solve();//倍增    scanf("%d",&q);    for(int i=1;i<=q;i++){//每个点的询问        int x,y;        scanf("%d%d",&x,&y);        if(co[x]!=co[y])puts("-1");        else{            int lca=LCA(x,y);            int L=work(x,lca),R=work(y,lca);            printf("%d\n",min(L,R));        }    }    return 0;}

一次最简单的考试。一半的人AK了。所以也不想写了。

原创粉丝点击