• 2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) E,F


    E

    • 题意: 一个起点,可以将火车点割掉,问最小的代价使得起点不能到达边界.
    • 思路: 拆点,火车点的入边到出边流量是割掉的价格,其他都是INF.最小割就是答案
    
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 45;
    const int M = N*N*2;
    const int INF = 0x3f3f3f3f;
    int n,m,k;
    
    struct node{
        int x,y;
    };
    struct E{
        int u,v,flow,nxt;
        E(){}
        E(int u,int v,int flow,int nxt):u(u),v(v),flow(flow),nxt(nxt){}
    }e[M*M];
    int sp,tp,tot;
    int head[M],dis[M];
    void init(){
        tot = 0;    memset(head,-1,sizeof head);
    }
    void add(int u,int v,int flow){
        e[tot] = (E){u,v,flow,head[u]};   head[u] = tot++;
        e[tot] = (E){v,u,0,head[v]};   head[v] = tot++;
    }
    int bfs(){
        static int q[M];
        int qtop = 0,qend = 0,u,v;
        memset(dis,-1,sizeof dis);
        dis[sp] = 0;    q[qend++] = sp;
        while(qtop != qend){
            u = q[qtop++];
            for(int i=head[u];~i;i=e[i].nxt){
                v = e[i].v;
                if(dis[v]==-1&&e[i].flow){
                    dis[v] = dis[u]+1;
                    q[qend++] = v;
                }
            }
        }
        return dis[tp] != -1;
    }
    int dfs(int u,int flow){
        int res = 0,v,d;
        if(u==tp)   return flow;
        for(int i=head[u];~i&&flow;i=e[i].nxt){
            v = e[i].v;
            if(dis[v]==dis[u]+1 && e[i].flow){
                d = dfs(v,min(e[i].flow,flow));
                e[i].flow -= d; e[i^1].flow +=d;
                res += d;   flow-=d;
            }
        }
        if(!res)    dis[u] = -2;
        return res;
    }
    int dinic(){
        int ans = 0;
        while(bfs()){
            ans += dfs(sp,INF);
    // cerr << ans << endl;
        }
        return ans;
    }
    char ma[N][N];
    int cost[N];
    const int dir[4][2] = {{1,0},{-1,0},{0,-1},{0,1}};
    int toP(int x,int y){
        return (x-1)*m+y;
    }
    void build(){
        int x,y,cp,np;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                cp = toP(i,j);
                for(int k=0;k<4;++k){
                    x = i + dir[k][0];  y = j + dir[k][1];
                    if(x<=0 || x>n || y<=0 || y>m){
                        add(cp+n*m,tp,INF); // 当前的出点到终点
                    }else{
                        np = toP(x,y);
                        add(cp+n*m,np,INF); // 当前的出点到下一点的入点
                    }
                }
    
                if(ma[i][j]=='B'){  // 起点
                    add(sp,cp,INF);
                }
                if(ma[i][j]>='a' && ma[i][j]<='z'){
                    add(cp,cp+n*m,cost[ma[i][j]-'a']);  // 当前点的入点到出点
                }else{
                    add(cp,cp+n*m,INF);
                }
            }
        }
    }
    
    
    int main(){
        scanf("%d%d%d",&m,&n,&k);
        tp = n*m*2+10; sp = tp+1;
        for(int i=1;i<=n;++i){
            scanf("%s",ma[i]+1);
        }
        for(int i=0;i<k;++i){
            scanf("%d",&cost[i]);
        }
        init();
        build();
    cerr << "START
    ";
        int ans = dinic();
        if(ans ==INF )  ans = -1;
        printf("%d
    ",ans);
        return 0;
    }
    
    

    F

    • 题意: 求奇数次矩形覆盖的面积
    • 思路: 扫描线,由于是奇数次覆盖,可以变成0次和1次覆盖,更新时直接将覆盖次数异或1翻转.
    
    #include<bits/stdc++.h>
    #define ll long long
    #define ls(r)   r<<1
    #define rs(r)   r<<1|1
    using namespace std;
    const int N = 1e5+10;
    
    struct node{
        int l,r;
        int lf,rf;
        int cover;
        ll len;
    }sgt[N<<3];
    int y[N<<1];
    struct Line{
        int x,y1,y2,state;
        bool operator < (Line oth)const{
            if(x == oth.x)  return state  > oth.state;
            return x < oth.x;
        }
    }line[N<<1];
    void push_up(int rt){
        sgt[rt].len = sgt[ls(rt)].len + sgt[rs(rt)].len;
    }
    void update(int rt){    // 翻转被覆盖的长度,原来被覆盖的取消掉,未被覆盖的添加上
        sgt[rt].len = sgt[rt].r - sgt[rt].l - sgt[rt].len;
    }
    void push_down(int rt){
        if(sgt[rt].cover){  // 当前区间被覆盖,更新子区间
            sgt[ls(rt)].cover ^= 1;
            sgt[rs(rt)].cover ^= 1;
            update(ls(rt));
            update(rs(rt));
            sgt[rt].cover = 0;
        }
    }
    
    void build(int l,int r,int rt){
        sgt[rt].l = y[l];   sgt[rt].r = y[r];
        sgt[rt].lf = l; sgt[rt].rf = r;
        if(r-l<=1)  return ;
        int m = (l+r)>>1;
        build(l,m,ls(rt));
        build(m,r,rs(rt));
    }
    void modify(int yl,int yr,int rt){
        int lf = sgt[rt].l , rf = sgt[rt].r;
        if(yl<=lf && yr>=rf){   // 完全覆盖
            update(rt);
            sgt[rt].cover ^=1;
            return ;
        }
        push_down(rt);
        if(yl<sgt[ls(rt)].r)    modify(yl,yr,ls(rt));
        if(yr>sgt[rs(rt)].l)    modify(yl,yr,rs(rt));
        push_up(rt);
    }
    int main(){
        int n,x1,y1,x2,y2;
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            y[i] = y1;  y[i+n] = y2;
            line[i] = (Line){x1,y1,y2,1};
            line[i+n] = (Line){x2,y1,y2,-1};
        }
        sort(y+1,y+1+n*2);
        sort(line+1,line+1+n*2);
        int m = unique(y+1,y+1+n*2)-y-1;
        build(1,m,1);
        ll ans = 0;
        for(int i=1;i<=n*2;++i){
            ans += sgt[1].len * (line[i].x - line[i-1].x);
            modify(line[i].y1,line[i].y2,1);
        }
        printf("%I64d
    ",ans);
    }
    
    
  • 相关阅读:
    生成密码
    生成密码
    C#委托
    C#委托
    C#委托
    最近所有博客
    win10 uwp 读写XML
    win10 uwp 读写XML
    win10 uwp 读写XML
    win10 uwp 绑定密码
  • 原文地址:https://www.cnblogs.com/xxrlz/p/11622677.html
Copyright © 2020-2023  润新知