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);
}