BZOJ4071: [APIO2015]八邻旁之桥
这个题也变成了权限题,不是很懂为什么。。。
反正没钱氪金。。。
这里附上洛谷的题面:
题目描述
一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 AA 和区域 BB。
每一块区域沿着河岸都建了恰好$1000000001$栋的建筑,每条岸边的建筑都从$ 0$ 编号到 $1000000000$。相邻的每对建筑相隔 $1$ 个单位距离,河的宽度也是 $1$ 个单位长度。
区域 $A$ 中的$ i$ 号建筑物恰好与区域 $B$ 中的 $i$ 号建筑物隔河相对。
城市中有$ N$ 个居民。第 $i$ 个居民的房子在区域$ P_i$ 的$ S_i$号建筑上,同时他的办公室坐落在$ Q_i$ 区域的$ T_i$ 号建筑上。
一个居民的房子和办公室可能分布在河的两岸,这样他就必须要搭乘船只才能从家中去往办公室,这种情况让很多人都觉得不方便。为了使居民们可以开车去工作,政府决定建造不超过 KK 座横跨河流的大桥。
由于技术上的原因,每一座桥必须刚好连接河的两岸,桥梁必须严格垂直于河流,并且桥与桥之间不能相交。
当政府建造最多$ K$ 座桥之后,设 $D_i$ 表示第$ i$ 个居民此时开车从家里到办公室的最短距离。请帮助政府建造桥梁,使得$ D_1 + D_2 + \cdots + D_N$ 最小。
输入输出格式
输入格式:
输入的第一行包含两个正整数$ K$ 和 $N$,分别表示桥的上限数量和居民的数量。
接下来 NN 行,每一行包含四个参数:$P_i, S_i, Q_i$ 和$ T_i$,表示第$ i$ 个居民的房子在区域 $P_i$的$ S_i$ 号建筑上,且他的办公室位于 $Q_i$ 区域的 $T_i$ 号建筑上。
输出格式:
输出仅为一行,包含一个整数,表示$ D_1 + D_2 + \cdots + D_N$ 的最小值。
输入输出样例
说明
【数据范围】
所有数据都保证:$P_i$ 和 $Q_i$ 为字符 “A” 和 “B” 中的一个, $0 \leq S_i, T_i \leq 1000000000$,同一栋建筑内可能有超过$ 1$ 间房子或办公室(或二者的组合,即房子或办公室的数量同时大于等于 $1$)。
子任务 1 (8 分)$K = 1$
$1 \leq N \leq 1000$
子任务 2 (14 分)$K = 1$
$1 \leq N \leq 100000$
子任务 3 (9 分)$K = 2$
$1 \leq N \leq 100$
子任务 4 (32 分)$K = 2$
$1 \leq N \leq 1000$
子任务 5 (37 分)$K = 2$
$1 \leq N \leq 100000$
题解Here!
又是一道把两个相似的题强行拼接在一起的题。。。
直接分类讨论:
当$k==1$的时候:
如果工作地点在一侧,那么路程就是$r-l$。
然后我们对于不在一侧的线段端点求个中位数,这样肯定能使总路程最小。
不过,$k==1$的情况没有必要线段树,直接丢进数组里排个序,就可以求出中位数了。
当$k==2$的时候:
取每个线段的中点,如果靠近左边的桥,就往左边过桥,否则往右边过桥。
枚举一个分割点,然后两边都是$k==1$的情况,用线段树求$\sum|\text{位置}-\text{中位数}|$。
附代码:(我分了两个$namespace$来写)
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 1000010 using namespace std; int n,k; int top=0,stack[MAXN]; long long ans=0; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline long long abs(const long long x){return x>0?x:-x;} namespace one{ int m=0; void main(){ char ch[2]; int x,y,p,q; for(int i=1;i<=n;i++){ scanf("%s",ch);x=read();p=ch[0]-'A'; scanf("%s",ch);y=read();q=ch[0]-'A'; if(p==q){ ans+=abs(x-y); continue; } else if(p==1)swap(x,y); m++; stack[++top]=x;stack[++top]=y; } sort(stack+1,stack+top+1); int mid=stack[top>>1]; for(int i=1;i<=top;i++)ans+=abs(mid-stack[i]); printf("%lld\n",ans+m); } } namespace two{ #define LSON rt<<1 #define RSON rt<<1|1 #define DATA(rt) a[rt].data #define SUM(rt) a[rt].sum #define LSIDE(rt) a[rt].l #define RSIDE(rt) a[rt].r int num=0; long long s[MAXN]; struct Line{ int x,y; friend bool operator <(const Line &p,const Line &q){ return (p.x+p.y)<(q.x+q.y); } }line[MAXN]; struct Segment_Tree{ long long data,sum; int l,r; }a[MAXN<<2]; inline void add_line(int x,int y){ num++; line[num].x=x;line[num].y=y; } inline void pushup(int rt){ DATA(rt)=DATA(LSON)+DATA(RSON); SUM(rt)=SUM(LSON)+SUM(RSON); } void buildtree(int l,int r,int rt){ LSIDE(rt)=l;RSIDE(rt)=r;DATA(rt)=SUM(rt)=0; if(l==r)return; int mid=l+r>>1; buildtree(l,mid,LSON); buildtree(mid+1,r,RSON); } void update(int k,int v,int rt){ DATA(rt)++;SUM(rt)+=v; if(LSIDE(rt)==RSIDE(rt))return; int mid=LSIDE(rt)+RSIDE(rt)>>1; if(k<=mid)update(k,v,LSON); else update(k,v,RSON); } long long query(int k,int rt){ if(LSIDE(rt)==RSIDE(rt))return 1LL*stack[LSIDE(rt)]*k; if(k<=DATA(LSON))return query(k,LSON); else return SUM(LSON)+query(k-DATA(LSON),RSON); } inline long long ask(int x){return SUM(1)-2LL*query(x,1);} void work(){ buildtree(1,top,1); for(int i=1;i<=num;i++){ line[i].x=lower_bound(stack+1,stack+top+1,line[i].x)-stack; line[i].y=lower_bound(stack+1,stack+top+1,line[i].y)-stack; update(line[i].x,stack[line[i].x],1); update(line[i].y,stack[line[i].y],1); s[i]=ask(i); } long long minn=s[num]; buildtree(1,top,1); for(int i=num;i>=1;i--){ update(line[i].x,stack[line[i].x],1); update(line[i].y,stack[line[i].y],1); minn=min(minn,s[i-1]+ask(num-i+1)); } printf("%lld\n",minn+ans); } void main(){ char ch[2]; int x,y,p,q; for(int i=1;i<=n;i++){ scanf("%s",ch);x=read();p=ch[0]-'A'; scanf("%s",ch);y=read();q=ch[0]-'A'; if(p==q){ ans+=abs(x-y); continue; } ans++; stack[++top]=x;stack[++top]=y; if(x>y)swap(x,y); add_line(x,y); } if(!num){ printf("%lld\n",ans); return; } sort(line+1,line+num+1); sort(stack+1,stack+top+1); top=unique(stack+1,stack+top+1)-stack-1; work(); } } int main(){ k=read();n=read(); if(k==1)one::main(); else two::main(); return 0; }