2017/10/23模拟赛总结

来源:互联网 发布:gartner云计算 编辑:程序博客网 时间:2024/06/15 10:58

丧心病狂图论场

T1 包裹快递

Vijos 1450

比较显然的二分
但是精度问题特别奇怪
O(nlogS)

#include<bits/stdc++.h>using namespace std;#define N 200010#define EPS 1e-6void rd(int &x){    char c;x=0;    while (c=getchar(),c<48);    do x=(x<<1)+(x<<3)+(c^48);    while (c=getchar(),c>=48);}int l[N],r[N],x[N],n;bool check(long double t){    long double now=0;    int i;    for (i=1;i<=n;i++){        now+=x[i]/t;        if (now<l[i]) now=l[i];        if (now>r[i]) return 0;    }    return 1;}int main(){    int i;    rd(n);    for (i=1;i<=n;i++) rd(l[i]),rd(r[i]),rd(x[i]);    long double L=0.001,R=2e13,ans;    for (i=1;i<=60;i++){        long double mid=(L+R)/2;        if (check(mid)) ans=mid,R=mid;        else L=mid;    }    printf("%.2Lf\n",ans);    return 0;}

T2 逃脱

Vijos 1452

首先要离散
直接建边是O(n2)的 选择不显示建边
用vector存每行/列的障碍物
每次只能走到同一行 同一列的障碍物的前一格 而且不能经过障碍物
就用二分查找一个最近的障碍物
进行BFS 用vector把每个点的dis记录下来
注意状态的判重 除起点外只会出现点在障碍物四周的情况
于是只需记录当前在哪个障碍物的哪个方向即可

然后要统计答案
每个出口的答案为同一列 同一行被障碍物阻挡之前的dis最小值+1 (也有可能一个点就在出口处 这就不需要+1)
那么对于每行每列 都把障碍物加进去排个序 然后统计每个区间内的最小值
答案就是二分查找到大于出口坐标的最小障碍物的区间最小值+1 或是正好在这一格内的dis
O((n+m)logn)

#include<bits/stdc++.h>using namespace std;#define N 100010#define A first#define B second#define INF (0x3f3f3f3f)void rd(int &x){    char c;x=0;    while (c=getchar(),c<48);    do x=(x<<1)+(x<<3)+(c^48);    while (c=getchar(),c>=48);}int X[4]={1,0,-1,0},Y[4]={0,1,0,-1};struct poi{    int x,y;}a[N],b[N];struct node{    int x,y,z,d;};int n,m,Sx,Sy,Tx[N<<2],Ty[N<<2],hx,hy;vector<pair<int,int> >Gx[N<<2],Gy[N<<2],ansx[N<<2],ansy[N<<2],Ansx[N<<2],Ansy[N<<2];queue<node>Q;bool vis[N][4];int Find(int a[],int h,int x){    int l=1,r=h,res=0;    while (l<=r){        int mid=(l+r)>>1;        if (x<=a[mid]) res=mid,r=mid-1;        else l=mid+1;    }    return res;}pair<int,int> Find1(vector<pair<int,int> > a,int x){    int l=0,r=a.size()-1,res=0;    while (l<=r){        int mid=(l+r)>>1;        if (x<=a[mid].A) res=mid,r=mid-1;        else l=mid+1;    }    return a[res];}pair<int,int> Find2(vector<pair<int,int> > a,int x){    int l=0,r=a.size()-1,res=0;    while (l<=r){        int mid=(l+r)>>1;        if (x>=a[mid].A) res=mid,l=mid+1;        else r=mid-1;    }    return a[res];}void BFS(){    Q.push((node){Sx,Sy,0,0});    Q.push((node){Sx,Sy,0,1});    while (!Q.empty()){        int x=Q.front().x,y=Q.front().y,z=Q.front().z,d=Q.front().d;        Q.pop();        pair<int,int> t;        if (!d){            ansx[x].push_back(make_pair(y,z));            if (Gx[x].size()){                t=Find1(Gx[x],y);                if (t.A>y){                    if (!vis[t.B][1]){                        vis[t.B][1]=1;                        Q.push((node){x,t.A-1,z+1,1});                    }                }                t=Find2(Gx[x],y);                if (t.A<y){                    if (!vis[t.B][3]){                        vis[t.B][3]=1;                        Q.push((node){x,t.A+1,z+1,1});                    }                }            }        }else{            ansy[y].push_back(make_pair(x,z));            if (Gy[y].size()){                t=Find1(Gy[y],x);                if (t.A>x){                    if (!vis[t.B][0]){                        vis[t.B][0]=1;                        Q.push((node){t.A-1,y,z+1,0});                    }                }                t=Find2(Gy[y],x);                if (t.A<x){                    if (!vis[t.B][2]){                        vis[t.B][2]=1;                        Q.push((node){t.A+1,y,z+1,0});                    }                }            }        }    }}int main(){    int i,j;    rd(n),rd(m),rd(Sx),rd(Sy);    Tx[++hx]=Sx;    Ty[++hy]=Sy;    for (i=1;i<=n;i++){        rd(a[i].x),rd(a[i].y);        Tx[++hx]=a[i].x;        Tx[++hx]=a[i].x+1;        Tx[++hx]=a[i].x-1;        Ty[++hy]=a[i].y;        Ty[++hy]=a[i].y+1;        Ty[++hy]=a[i].y-1;    }    for (i=1;i<=m;i++){        rd(b[i].x),rd(b[i].y);        Tx[++hx]=b[i].x;        Ty[++hy]=b[i].y;    }    sort(Tx+1,Tx+1+hx);    sort(Ty+1,Ty+1+hy);    hx=unique(Tx+1,Tx+1+hx)-Tx-1;    hy=unique(Ty+1,Ty+1+hy)-Ty-1;    Sx=Find(Tx,hx,Sx);    Sy=Find(Ty,hy,Sy);    for (i=1;i<=n;i++){        a[i].x=Find(Tx,hx,a[i].x);        a[i].y=Find(Ty,hy,a[i].y);        Gx[a[i].x].push_back(make_pair(a[i].y,i));        Gy[a[i].y].push_back(make_pair(a[i].x,i));        ansx[a[i].x].push_back(make_pair(a[i].y,-1));        ansy[a[i].y].push_back(make_pair(a[i].x,-1));    }    for (i=1;i<=hx;i++) sort(Gx[i].begin(),Gx[i].end());    for (i=1;i<=hy;i++) sort(Gy[i].begin(),Gy[i].end());    BFS();    for (i=1;i<=hx;i++){        sort(ansx[i].begin(),ansx[i].end());        int tmp=INF;        for (j=0;j<ansx[i].size();j++){            if (!~ansx[i][j].B) Ansx[i].push_back(make_pair(ansx[i][j].A,tmp)),tmp=INF;            else tmp=min(tmp,ansx[i][j].B);        }        Ansx[i].push_back(make_pair(hy+1,tmp));    }    for (i=1;i<=hy;i++){        sort(ansy[i].begin(),ansy[i].end());        int tmp=INF;        for (j=0;j<ansy[i].size();j++){            if (!~ansy[i][j].B) Ansy[i].push_back(make_pair(ansy[i][j].A,tmp)),tmp=INF;            else tmp=min(tmp,ansy[i][j].B);        }        Ansy[i].push_back(make_pair(hx+1,tmp));    }    for (i=1;i<=m;i++){        int ans=INF;        b[i].x=Find(Tx,hx,b[i].x);        b[i].y=Find(Ty,hy,b[i].y);        pair<int,int> tmp;        if (ansx[b[i].x].size()){            tmp=Find1(Ansx[b[i].x],b[i].y+1);            if (tmp.A>b[i].y) ans=min(ans,tmp.B+1);            tmp=Find1(ansx[b[i].x],b[i].y);            if (~tmp.B && tmp.A==b[i].y) ans=min(ans,tmp.B);        }        if (ansy[b[i].y].size()){            tmp=Find1(Ansy[b[i].y],b[i].x+1);            if (tmp.A>b[i].x) ans=min(ans,tmp.B+1);            tmp=Find1(ansy[b[i].y],b[i].x);            if (~tmp.B && tmp.A==b[i].x) ans=min(ans,tmp.B);        }        printf("%d\n",ans==INF?-1:ans);    }    return 0;}

T3 天才黑客

SDOI2017 Round2 T1
一道特别难写而且码量巨大的图论题

首先字典树上的边权是没有用的 对于两个点的lcp其实就是在字典树上的lca
但是不能每次都求lca 这样显然会超时
本题中的点其实没有什么用 可以把所有边在新图中看做点 并且连边
然后需要考虑优化建边
把在原图中的每个点相连的边找出来 用他们在字典树上的点构建一棵虚树
此时虚树上的一个点就是它两两子树内的点的lca 或这个点和子树内某个点的lca
但是在子树内直接连边 边数仍然很大
观察到子树是一个连续的区间 可以用线段树上的一个点表示一个区间 然后再这个点上连边
这时候就需要建两棵线段树 分别管理入边和出边 管理的下标是虚树内的dfn
入边节点向入线段树对应叶子节点连边 边权即为原图上这条边的边权
出线段树叶子节点向对应出边节点连边 边权为0
然后在线段树内 入线段树的子节点向父节点连边 出线段树相反

枚举作为lca的点
两两子树内连边时是一段连续的区间向另两段区间(可能为一段)连边
因此需要一个辅助节点 把入线段树的区间都连到这个点 再连到出线段树的另外两个区间
入线段树连的边边权为当前枚举的点的深度
这个点也要和子树内连边

新图就建立完成了
但是这样无法得到到每个点的距离
可以先建立一个起点 当做1节点的入边 边权为0
然后在中间虚树处理过程中 每个原图上的点新开一个节点 把每个入线段树的叶子节点都连到这个点 边权为0

接下来只要跑一遍Dijkstra即可
O(nlog2n)

#include<bits/stdc++.h>using namespace std;#define N 50010#define M 20010#define K 1000010inline void rd(int &x){    char c;x=0;    while (c=getchar(),c<48);    do x=(x<<1)+(x<<3)+(c^48);    while (c=getchar(),c>=48);}inline void pt(long long x){    if (!x) putchar('0');    else{        static int s[20],t;        for (t=0;x;x/=10) s[t++]=x%10;        while (t) putchar(s[--t]^48);    }    putchar('\n'); }struct edge{    int nxt,t,s;}e[K<<2];int head[K],edge_cnt;inline void add_edge(int x,int y,int z){    e[edge_cnt]=(edge){head[x],y,z};    head[x]=edge_cnt++;}struct INOUTEdge{    int nxt,x;}w[N<<2];int G1[N],G2[N],G_cnt;inline void add_G(int *G,int x,int y){    w[G_cnt]=(INOUTEdge){G[x],y};    G[x]=G_cnt++;}int val[N],Tid[N],poiID[N];struct Trie_Tree{    struct Edge{        int nxt,t;    }E[M];    int Head[M],Edge_cnt,fa[M],dep[M],siz[M],son[M],top[M],dfs_cnt,dfn[N],ed[N];    inline void Add_edge(int x,int y){        E[Edge_cnt]=(Edge){Head[x],y};        Head[x]=Edge_cnt++;    }    void clear(){        memset(Head,-1,sizeof(Head));        dfs_cnt=Edge_cnt=0;    }    void dfs(int x,int f){        fa[x]=f;        dep[x]=dep[f]+1;        siz[x]=1;        son[x]=0;        int i;        for (i=Head[x];~i;i=E[i].nxt){            int to=E[i].t;            if (to==f) continue;            dfs(to,x);            siz[x]+=siz[to];            if (siz[to]>siz[son[x]]) son[x]=to;        }    }    void dfs1(int x,int tp){        dfn[x]=++dfs_cnt;        top[x]=tp;        if (son[x]) dfs1(son[x],tp);        int i;        for (i=Head[x];~i;i=E[i].nxt){            int to=E[i].t;            if (to==fa[x] || to==son[x]) continue;            dfs1(to,to);        }        ed[x]=dfs_cnt;    }    int LCA(int x,int y){        while (top[x]!=top[y]){            if (dep[top[x]]<dep[top[y]]) y=fa[top[y]];            else x=fa[top[x]];        }        return dep[x]<dep[y]?x:y;    }    void init(){        dfs(1,0);        dfs1(1,1);    }}Trie;int vcnt,a[N<<1],h,vid1[N<<1],vid2[N<<1],vdfn[N<<1],ved[N<<1],vfa[N<<1],tmp[N<<1];struct Virtual_Tree{    #define Lc p<<1    #define Rc p<<1|1    struct Segment_Tree_out{        int g[N<<3];        void build(int l,int r,int p){            g[p]=++vcnt;            if (l==r){                vid1[l]=g[p];                return;            }            int mid=(l+r)>>1;            build(l,mid,Lc);            build(mid+1,r,Rc);            add_edge(g[p],g[Lc],0);            add_edge(g[p],g[Rc],0);        }        void add(int l,int r,int p,int pl,int pr,int x,int a){            if (l==pl && r==pr){                add_edge(x,g[p],a);                return;            }            int mid=(l+r)>>1;            if (pr<=mid) add(l,mid,Lc,pl,pr,x,a);            else if (pl>mid) add(mid+1,r,Rc,pl,pr,x,a);            else add(l,mid,Lc,pl,mid,x,a),add(mid+1,r,Rc,mid+1,pr,x,a);        }    }T1;    struct Segment_Tree_in{        int g[N<<3];        void build(int l,int r,int p){            g[p]=++vcnt;            if (l==r){                vid2[l]=g[p];                return;            }            int mid=(l+r)>>1;            build(l,mid,Lc);            build(mid+1,r,Rc);            add_edge(g[Lc],g[p],0);            add_edge(g[Rc],g[p],0);        }        void add(int l,int r,int p,int pl,int pr,int x,int a){            if (l==pl && r==pr){                add_edge(g[p],x,a);                return;            }            int mid=(l+r)>>1;            if (pr<=mid) add(l,mid,Lc,pl,pr,x,a);            else if (pl>mid) add(mid+1,r,Rc,pl,pr,x,a);            else add(l,mid,Lc,pl,mid,x,a),add(mid+1,r,Rc,mid+1,pr,x,a);        }    }T2;    static bool cmp(int x,int y){        return Trie.dfn[x]<Trie.dfn[y];    }    inline bool contain(int x,int y){        return Trie.dfn[x]>=Trie.dfn[y] && Trie.dfn[x]<=Trie.ed[y];    }    void vbuild(){        int i;        sort(a+1,a+1+h,cmp);        for (i=1;i<h;i++) a[h+i]=Trie.LCA(a[i],a[i+1]);        sort(a+1,a+h*2,cmp);        h=unique(a+1,a+h*2)-a-1;        int h1=0;        for (i=1;i<=h;i++){            vdfn[a[i]]=i;            while (h1 && !contain(a[i],tmp[h1])) ved[tmp[h1--]]=i-1;            vfa[a[i]]=tmp[h1];            tmp[++h1]=a[i];        }        while (h1) ved[tmp[h1--]]=h;    }    void solve(int x){        int i;        h=0;        for (i=G1[x];~i;i=w[i].nxt) a[++h]=Tid[w[i].x];        for (i=G2[x];~i;i=w[i].nxt) a[++h]=Tid[w[i].x];        vbuild();        T1.build(1,h,1);        T2.build(1,h,1);        for (i=G1[x];~i;i=w[i].nxt) add_edge(vid1[vdfn[Tid[w[i].x]]],w[i].x,0);        for (i=G2[x];~i;i=w[i].nxt) add_edge(w[i].x,vid2[vdfn[Tid[w[i].x]]],val[w[i].x]);        for (i=2;i<=h;i++){            int p=++vcnt;            int x1=a[i],y1=vfa[a[i]];            T2.add(1,h,1,vdfn[x1],ved[x1],p,Trie.dep[y1]);            T1.add(1,h,1,vdfn[y1],vdfn[x1]-1,p,0);            if (ved[x1]<ved[y1]) T1.add(1,h,1,ved[x1]+1,ved[y1],p,0);        }        poiID[x]=++vcnt;        for (i=1;i<=h;i++){            int x1=a[i];            T1.add(1,h,1,vdfn[x1],ved[x1],vid2[vdfn[x1]],Trie.dep[x1]);            add_edge(vid2[vdfn[x1]],poiID[x],0);        }    }}vTree;struct node{    int x;    long long d;    bool operator <(const node &_)const{        return d<_.d;    }};struct heap{    #define swap(x,y) (tt=x,x=y,y=tt)    node A[K],tt;    int Top;    void push(node x){        A[++Top]=x;        int i=Top;        while (i>1){            int j=i>>1;            if (A[i]<A[j]) swap(A[i],A[j]),i=j;            else break;        }    }    void pop(){        A[1]=A[Top--];        int i=1;        while ((i<<1)<=Top){            int j=i<<1;            if (j<Top && A[j+1]<A[j]) j++;            if (A[j]<A[i]) swap(A[i],A[j]),i=j;            else break;        }    }}Q;long long dis[K];bool vis[K];void Dijkstra(int st){    memset(dis,63,sizeof(dis));    memset(vis,0,sizeof(vis));    int i;    Q.push((node){st,0});    dis[st]=0;    while (Q.Top){        int x=Q.A[1].x;        long long z=Q.A[1].d;        Q.pop();        if (vis[x]) continue;        vis[x]=1;        for (i=head[x];~i;i=e[i].nxt){            int to=e[i].t,Val=e[i].s;            if (dis[to]>z+Val){                dis[to]=z+Val;                Q.push((node){to,dis[to]});            }        }    }}void Clear(){    memset(head,-1,sizeof(head));    memset(G1,-1,sizeof(G1));    memset(G2,-1,sizeof(G2));    edge_cnt=G_cnt=0;    Trie.clear();}int main(){    int Case;    rd(Case);    Trie.dep[0]=-1;    while (Case--){        Clear();        int n,m,k,i;        rd(n),rd(m),rd(k);        for (i=1;i<=m;i++){            int x,y;            rd(x),rd(y),rd(val[i]),rd(Tid[i]);            add_G(G1,x,i);//出边             add_G(G2,y,i);//入边         }        for (i=1;i<k;i++){            int x,y,z;            rd(x),rd(y),rd(z);            Trie.Add_edge(x,y);        }        Trie.init();        m++;        val[m]=0;        Tid[m]=1;        add_G(G2,1,m);//另造一个起点        vcnt=m;        for (i=1;i<=n;i++) vTree.solve(i);        Dijkstra(m);        for (i=2;i<=n;i++) pt(dis[poiID[i]]);    }    return 0;}

Date:2017/10/25 (Updated 2017/11/7)
By CalvinJin

原创粉丝点击