【题解】 CF936E Iqea 平面图分治+点分树
作者:互联网
考虑怎么求图上任意两点距离。
考虑分治,每次找一条竖着的线段,把区域划分成两半,计算所有点到切分线段的距离,于是穿过这条切分线的答案就可以被计算出来了。
那么求一个点到点集最短的距离,动态更新点集,怎么做?
不难发现,可以把分治的过程储存下来,具体来说,以点分树的形式储存。查询在点分树上查询即可。
code
// 珍爱生命,远离 unordered
#pragma GCC opimize("Ofast")
#include <bits/stdc++.h>
#define debug(...) fprintf(stderr ,__VA_ARGS__)
#define __FILE(x)\
freopen(#x".in" ,"r" ,stdin);\
freopen(#x".out" ,"w" ,stdout)
#define LL long long
const int MX = 3e5 + 23;
const LL MOD = 998244353;
typedef std::pair<int ,int> pi;
int read(){
char k = getchar(); int x = 0;
while(k < '0' || k > '9') k = getchar();
while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
return x;
}
pi QWQ[MX];
struct HA{
size_t operator ()(const pi &t)const{
return t.first * 300001ull + t.second;
}
};
class BIT{
int bound;
std::vector<int> data;
public:
void resize(int cap){
bound = cap + 1;
data = std::vector<int>(bound ,1e8);
}
void change(int x ,int v){
while(x < bound){
data[x] = std::min(data[x] ,v);
x += x & -x;
}
}
int getmin(int x){
int ans = 1e8;
while(x > 0){
ans = std::min(ans ,data[x]);
x -= x & -x;
}
return ans;
}
}ds[MX][2];
const int dx[] = {0 ,0 ,1 ,-1};
const int dy[] = {1 ,-1 ,0 ,0};
std::unordered_map<pi ,int ,HA> buc;
int bel[MX];
std::vector<int> S[MX];
std::vector<int> to[MX];
int n ,q;
int head[MX] ,tot = 1;
struct edge{
int node ,next;
}h[MX << 1];
void addedge(int u ,int v ,int flg = 1){
h[++tot] = (edge){v ,head[u]} ,head[u] = tot;
if(flg) addedge(v ,u ,false);
}
int vis[MX];
int cnt ,w[MX] ,miny[MX] ,maxy[MX];
void dfs(int x ,int y ,int f){
if(f){
addedge(cnt + 1 ,f);
//debug("link %d %d\n" ,cnt + 1 ,f);
}
int uy = y ,dy = y;
while(buc.find({x ,uy + 1}) != buc.end()) ++uy;
while(buc.find({x ,dy - 1}) != buc.end()) --dy;
int cur = ++cnt;
for(int i = dy ; i <= uy ; ++i){
S[cur].push_back(buc[{x ,i}]);
bel[buc[{x ,i}]] = cur;
}
for(int i = dy ; i <= uy ; ++i){
if(buc.find({x + 1 ,i}) != buc.end() && !bel[buc[{x + 1 ,i}]]) dfs(x + 1 ,i ,cur);
if(buc.find({x - 1 ,i}) != buc.end() && !bel[buc[{x - 1 ,i}]]) dfs(x - 1 ,i ,cur);
}
miny[cur] = dy;
maxy[cur] = uy;
w[cur] = uy - dy + 1;
debug("%d: %d~[%d ,%d]\n" ,cur ,x ,dy ,uy);
}
int size[MX] ,mxsz[MX] ,subsz ,G;
void GetG(int x ,int f){
size[x] = w[x] ,mxsz[x] = 0;
for(int i = head[x] ,d ; i ; i = h[i].next){
if((d = h[i].node) == f || vis[d]) continue;
GetG(d ,x) ,size[x] += size[d];
mxsz[x] = std::max(mxsz[x] ,size[d]);
}
mxsz[x] = std::max(mxsz[x] ,subsz - size[x]);
if(mxsz[x] < mxsz[G]) G = x;
}
int depth[MX];
int dis[20][MX] ,from[20][MX];
int cv[MX];
void doit(int R ,int dep){
std::vector<int> visit;
std::queue<int> Q;
for(auto i : S[R]){
dis[dep][i] = 0 ,from[dep][i] = QWQ[i].second - miny[R] + 1;
cv[i] = 1;
visit.push_back(i);
Q.push(i);
}
while(!Q.empty()){;
int x = Q.front(); Q.pop();
for(auto i : to[x]){
if(!vis[bel[i]] && !cv[i]){
cv[i] = 1;
from[dep][i] = from[dep][x];
dis[dep][i] = dis[dep][x] + 1;
visit.push_back(i);
Q.push(i);
}
}
}
for(auto i : visit) cv[i] = false;
ds[R][0].resize(w[R]);
ds[R][1].resize(w[R]);
}
int ff[MX];
void solve(int x ,int dep){
depth[x] = dep;
debug("> %d\n" ,x);
vis[x] = true; doit(x ,dep);
for(int i = head[x] ,d ; i ; i = h[i].next){
if(vis[d = h[i].node]) continue;
mxsz[G = 0] = subsz = size[d];
GetG(d ,x) ,ff[G] = x;
solve(G ,dep + 1);
}
}
void change(int x ,int y){
int dep = depth[bel[buc[{x ,y}]]];
for(int u = bel[buc[{x ,y}]] ; u ; u = ff[u] ,--dep){
int id = buc[{x ,y}];
int inter = from[dep][id] ,rinter = w[u] - inter + 1;
int length = dis[dep][id];
ds[u][0].change(inter ,length - inter);
ds[u][1].change(rinter ,length - rinter);
}
}
int query(int x ,int y){
int ans = 1e8 ,dep = depth[bel[buc[{x ,y}]]];
for(int u = bel[buc[{x ,y}]] ; u ; u = ff[u] ,--dep){
int id = buc[{x ,y}];
int inter = from[dep][id] ,rinter = w[u] - inter + 1;
int length = dis[dep][id];
ans = std::min(ans ,length + inter + ds[u][0].getmin(inter));
ans = std::min(ans ,length + rinter + ds[u][1].getmin(rinter));
}
return ans > n ? -1 : ans;
}
void buildtree(){
for(auto o : buc){
int x = o.first.first ,y = o.first.second;
for(int i = 0 ,tx ,ty ; i < 4 ; ++i){
tx = x + dx[i] ,ty = y + dy[i];
if(buc.find({tx ,ty}) != buc.end()){
to[o.second].push_back(buc[{tx ,ty}]);
}
}
}
auto i = buc.begin();
dfs(i->first.first ,i->first.second ,0);
mxsz[G = 0] = subsz = n;
GetG(1 ,0) ,solve(G ,0);
}
int main(){
n = read();
for(int i = 1 ,x ,y ; i <= n ; ++i){
x = read() ,y = read();
QWQ[i] = {x ,y};
buc[{x ,y}] = i;
}
buildtree();
q = read();
for(int i = 1 ,op ,x ,y ; i <= q ; ++i){
op = read() ,x = read() ,y = read();
if(op == 1) change(x ,y);
else printf("%d\n" ,query(x ,y));
}
return 0;
}
标签:std,int,题解,dep,CF936E,Iqea,ans,buc,inter 来源: https://www.cnblogs.com/imakf/p/15016134.html