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\n";
    int ans = dinic();
    if(ans ==INF )  ans = -1;
    printf("%d\n",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\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/xxrlz/p/11622677.html