题目: 传送门
思路:
网上几乎没有这题的题解,GYM上面过的人也很少,写这篇博客的初衷只是为了有想要看代码的同学了解一下.
思路跟题解差不多,对于每个区间我们用虚点表示,类似于线段树的编号方式,然后建立两个线段树,一颗为出边(内部自下而上建边),一颗为进边(内部自上而下建边)。进边线段树的叶子节点向出边线段树的对应叶子节点建一条有向边。
对于我们m次的加边操作,我先求出a,b两个区间的编号有哪些,然后设立两个虚点 c1,c2 ,a和c1全都建一条为0边,c1 c2建一条花费为我们当前这条新边的花费, c2 和b 再全建一条边.
最后的结果就是多起点的最短路问题,基本做法是把所有起点在开始的时候都放进队列,然后进行的基本的最短路即可.
最后要注意的是数组大小的计算.本菜鸡RE了一晚上才发现这道题要建的边远远超过了自己的数组大小…
Ac_Code
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <queue>
#define fir first
#define sec second
using namespace std;
typedef pair<int,long long> P;
const int maxn = 1e5+7;
const long long INF = 1e18;
int n,m,pi,qi,cnt,e,cur;
int Node[maxn<<4];
int head[maxn<<4];
P edge[maxn*80];
int nex[maxn*80];
int h1,h2;
int vx[maxn];
int vy[maxn];
void add(int x,int y,long long cost) {
//printf("%d %d %lld!\n", x,y,cost);
edge[++e] = P(y,cost);
nex[e] = head[x];
head[x] = e;
}
void build1(int l,int r,int num) {
//printf("This %d %d %d\n",l,r,num);
cnt = max(cnt,num);
if(l==r) {
Node[l] = num;
return ;
}
int mid = (l+r) >>1;
build1(l,mid,num<<1);
build1(mid+1,r,num<<1|1);
add(num<<1,num,0);
add(num<< 1|1,num,0);
}
void build2(int l,int r,int num) {
if(l==r) {
add(num+cnt,num,0);
return ;
}
int mid = (l+r) >>1;
build2(l,mid,num<<1);
build2(mid+1,r,num<<1|1);
add(num+cnt,(num<<1)+cnt,0);
add(num+cnt,(num<<1|1)+cnt,0);
}
void quriy1(int l,int r,int num,int le,int ri) {
if(le<=l && r<=ri) {
vx[h1++] = num;
return ;
}
int mid = (l+r) >> 1;
if(le<=mid) quriy1(l,mid,num<<1,le,ri);
if(mid< ri) quriy1(mid+1,r,num<<1|1,le,ri);
}
void quriy2(int l,int r,int num,int le,int ri) {
if(le<=l && r<=ri) {
vy[h2++] = num;
return ;
}
int mid = (l+r) >> 1;
if(le<=mid) quriy2(l,mid,num<<1,le,ri);
if(mid< ri) quriy2(mid+1,r,num<<1|1,le,ri);
}
int sta[maxn],las[maxn];
long long dis[maxn<<4];
int vis[maxn<<4];
int flag[maxn<<4];
struct cmp1
{
bool operator () (P a,P b) {
return a.sec>b.sec;
}
};
priority_queue< P,vector<P>,cmp1> q;
void disjike() {
for(int i = 0;i<=cur;i++) dis[i] = INF;
for(int i=0;i<qi;i++) {
int u = Node[sta[i]+n];
dis[u] = 0;
q.push(P(u,0));
}
while(!q.empty()) {
P top = q.top();
q.pop();
if(vis[top.fir] == 1 || dis[top.fir] == INF) continue;
vis[top.fir] = 1;
for(int i=head[top.fir];i;i=nex[i]) {
P x = edge[i];
if(dis[x.fir] > dis[top.fir] + x.sec) {
dis[x.fir] = dis[top.fir] + x.sec;
q.push(P(x.fir,dis[x.fir]));
}
}
}
return ;
}
int main() {
scanf("%d%d%d%d",&n,&m,&pi,&qi);
build1(1,n+n,1);
build2(1,n+n,1);
cur = cnt*2;
for(int i=0;i<m;i++) {
int l,r,a,b;
long long c;
scanf("%d%d%d%d%lld",&l,&r,&a,&b,&c);
h1=h2=0;
if(c == 0) continue;
quriy1(1,n+n,1,l,r);
quriy2(1,n+n,1,a+n,b+n);
for(int i=0;i<h1;i++) add(vx[i],cur+1,0);
for(int i=0;i<h2;i++) add(cur+2,vy[i]+cnt,0);
add(cur+1,cur+2,c);
cur+=2;
for(int i=0;i<h2;i++) add(vy[i],cur+1,0);
for(int i=0;i<h1;i++) add(cur+2,vx[i]+cnt,0);
add(cur+1,cur+2,c);
cur+=2;
}
for(int i = 0;i<pi;i++) {
scanf("%d",&las[i]);
}
for(int i = 0;i<qi;i++) {
scanf("%d",&sta[i]);
}
disjike();
long long ans = 0;
for(int i=0;i<pi;i++) {
ans = max(ans,dis[Node[las[i]]]);
}
if(ans == INF) printf("boring game\n");
else printf("%lld\n",ans);
return 0;
}