luogu P5471 [NOI2019] 弹跳
https://www.luogu.com.cn/problem/P5471
一眼树套树,但是发现空间会炸
于是采用空间一个log的线段树套set
然而发现如果连边的话空间还是会炸
发现可以不用连边,考虑dijkstra
把二维结构维护出来,然后每次查询一个矩阵,把矩阵里的点全部便利一边
因为一个点最多被出队一次,所以时间复杂度是对的 l o g 2 log^2 log2
code:
#include<bits/stdc++.h>
#define N 70050
#define pi pair<int, int>
#define mkp make_pair
#define fi first
#define se second
using namespace std;
set<pi> S[N << 2];
void add(int rt, int l, int r, int x, pi o) {
S[rt].insert(o);
if(l == r) return ;
int mid = (l + r) >> 1;
if(x <= mid) add(rt << 1, l, mid, x, o);
else add(rt << 1 | 1, mid + 1, r, x, o);
}
struct MAT {
int l, r, ll, rr, dis;
bool operator < (const MAT &o) const {
return dis > o.dis;
}
};
int vis[N], ls[N], tot;
void find(int rt, int l, int r, MAT o) { //printf("%d %d %d %d %d %d\n", l, r, o.l, o.r, o.ll, o.rr);
if(o.l <= l && r <= o.r) {// printf("*");return ;
set<pi>::iterator it;
while(1) {
it = S[rt].lower_bound(mkp(o.ll, 0));
int y = (*it).fi, id = (*it).se;
// printf("** %d %d %d\n", y, id, S[rt].size());
if(y > o.rr) break;
if(!vis[id]) ls[++ tot] = id;
S[rt].erase(it);
}
return ;
}
int mid = (l + r) >> 1;
if(o.l <= mid) find(rt << 1, l, mid, o);
if(o.r > mid) find(rt << 1 | 1, mid + 1, r, o);
}
vector<MAT> g[N];
priority_queue<MAT> q;
int dis[N], n, m, w, h;
void loof(int u) {
vis[u] = 1;
for(int i = 0; i < g[u].size(); i ++) {
g[u][i].dis += dis[u];
q.push(g[u][i]);
}
}
int main() {
// freopen("a.in","r",stdin);
scanf("%d%d%d%d", &n, &m, &w, &h);
for(int i = 1; i <= n; i ++) {
int x, y;
scanf("%d%d", &x, &y);
add(1, 1, w, x, mkp(y, i));
}
for(int i = 1; i <= (w << 2); i ++) S[i].insert(mkp(h + 1, 0));
for(int i = 1; i <= m; i ++) {
MAT o; int u;
scanf("%d%d%d%d%d%d", &u, &o.dis, &o.l, &o.r, &o.ll, &o.rr);
g[u].push_back(o);
}
loof(1);
while(q.size()) {
MAT o = q.top(); q.pop();
tot = 0; find(1, 1, w, o);
// for(int i = 1; i <= tot; i ++) printf("%d ", ls[i]); printf(" : %d\n", o.dis);
for(int i = 1; i <= tot; i ++) {
dis[ls[i]] = o.dis;
loof(ls[i]);
}
}
for(int i = 2; i <= n; i ++) printf("%d\n", dis[i]);
return 0;
}