ezoj 1235 [RYOI2018]榊野木乃实
小A发生了$n$件事,第$i$件事记作一个点$(x_i,y_i)$
小B可以原谅他$m$次,第$i$次的原谅点为$(x_i,y_i)$,同时有一个原谅值$w_i$,每次只能原谅一件事情,且只能原谅与原谅点的曼哈顿距离不超过$w_i$的事情
问最多能原谅几件事情,同时输出方案
对于100%的数据,n<=20'000,m<=20'000,|xi|,|yi|<=100'000'000。
数据在值域范围内随机
看到“数据在值域范围内随机”后就知道这是一个毒瘤板子题了……
相当于对于每一个原谅点,向所有可以原谅的事情连边,然后这是一个二分图,在上面跑最大匹配就行了
然后数据比较大,所以可以用KDTree优化连边,然后在上面跑dinic算法
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 2e6 + 10, inf = 0x3f3f3f3f; 5 int head[N], rest[N], to[N], f[N], S, T, cnt, ed = 1; 6 void _add(int u, int v, int f) { to[++ ed] = v, :: f[ed] = f, rest[ed] = head[u], head[u] = ed; } 7 void add(int u, int v, int f) { _add(u, v, f), _add(v, u, 0); } 8 9 int D, n, m, skill_id[N], thing_id[N], cur[N]; 10 11 inline int read() { 12 int x=0,f=1;char c=getchar(); 13 for(; c<'0'||'9'<c; c=getchar())if(c=='-')f=-1; 14 for(; '0'<=c&&c<='9'; c=getchar())x=(x<<3)+(x<<1)+c-'0'; 15 return x*f; 16 } 17 18 struct P { 19 int d[2], x[2], y[2], ch[2], id; 20 P() {} 21 P(int x, int y) { d[0] = x, d[1] = y; } 22 void init() { 23 x[0] = x[1] = d[0]; 24 y[0] = y[1] = d[1]; 25 ch[0] = ch[1] = 0; 26 } 27 int getdis(P b) { 28 return abs(d[0] - b.d[0]) + abs(d[1] - b.d[1]); 29 } 30 void update(P p) { 31 x[0] = min(x[0], p.x[0]); 32 x[1] = max(x[1], p.x[1]); 33 y[0] = min(y[0], p.y[0]); 34 y[1] = max(y[1], p.y[1]); 35 } 36 pair<int, int> dis(P p) { 37 int dis[4], tot = 0, mn, mx; 38 for(int i = 0 ; i < 2 ; ++ i) 39 for(int j = 0 ; j < 2 ; ++ j) 40 dis[tot ++] = p.getdis(P(x[i], y[j])); 41 mx = *max_element(dis, dis + tot); 42 mn = *min_element(dis, dis + tot); 43 tot = 0; 44 if(x[0] <= p.d[0] && p.d[0] <= x[1]) { 45 dis[tot ++] = abs(y[0] - p.d[1]); 46 dis[tot ++] = abs(y[1] - p.d[1]); 47 } 48 if(y[0] <= p.d[1] && p.d[1] <= y[1]) { 49 dis[tot ++] = abs(x[0] - p.d[0]); 50 dis[tot ++] = abs(x[1] - p.d[0]); 51 } 52 if(x[0] <= p.d[0] && p.d[0] <= x[1] && 53 y[0] <= p.d[1] && p.d[1] <= y[1]) { 54 dis[tot ++] = 0; 55 } 56 if(tot) mn = min(mn, *min_element(dis, dis + tot)); 57 return make_pair(mn, mx); 58 } 59 } p[N]; 60 bool operator < (P a, P b) { return a.d[D] < b.d[D]; } 61 62 namespace DINIC { 63 int dis[N]; 64 int bfs() { 65 for(int i = 1 ; i <= cnt ; ++ i) dis[i] = -1; 66 queue<int> q; 67 q.push(S); 68 dis[S] = 1; 69 while(q.size()) { 70 int u = q.front(); q.pop(); 71 for(int i = head[u] ; i ; i = rest[i]) { 72 int v = to[i]; 73 if(f[i] && dis[v] == -1) { 74 dis[v] = dis[u] + 1; 75 q.push(v); 76 } 77 } 78 } 79 return dis[T] != -1; 80 } 81 int dfs(int u, int flow) { 82 if(u == T || !flow) return flow; 83 int use = 0; 84 for(int &i = cur[u] ; i ; i = rest[i]) { 85 int v = to[i]; 86 if(f[i] && dis[v] == dis[u] + 1) { 87 int a = dfs(v, min(f[i], flow - use)); 88 f[i] -= a; 89 f[i ^ 1] += a; 90 use += a; 91 if(use == flow) break; 92 } 93 } 94 if(!use) dis[u] = -1; 95 return use; 96 } 97 int sol() { 98 int res = 0; 99 while(bfs()) { 100 for(int i = 1 ; i <= cnt ; ++ i) cur[i] = head[i]; 101 res += dfs(S, inf); 102 } 103 return res; 104 } 105 } 106 107 namespace KDT { 108 int root, id[N], pos[N]; 109 int build(int l, int r, int d) { 110 D = d; 111 int mid = (l + r) >> 1; 112 nth_element(p + l, p + mid, p + r + 1); 113 p[mid].init(); 114 115 id[mid] = ++ cnt; 116 pos[mid] = ++ cnt, thing_id[cnt] = p[mid].id; 117 add(id[mid], pos[mid], inf); 118 add(pos[mid], T, 1); 119 120 if(l <= mid - 1) { 121 p[mid].ch[0] = build(l, mid - 1, d ^ 1); 122 p[mid].update(p[p[mid].ch[0]]); 123 add(id[mid], id[p[mid].ch[0]], inf); 124 } 125 126 if(mid + 1 <= r) { 127 p[mid].ch[1] = build(mid + 1, r, d ^ 1); 128 p[mid].update(p[p[mid].ch[1]]); 129 add(id[mid], id[p[mid].ch[1]], inf); 130 } 131 return mid; 132 } 133 inline void met_build() { 134 root = build(1, n, 0); 135 } 136 137 void dfs(int u, int ID, P o, int w) { 138 if(!u) return ; 139 if(p[u].getdis(o) <= w) add(ID, pos[u], 1); 140 pair<int, int> dis = p[u].dis(o); 141 int mndis = dis.first, mxdis = dis.second; 142 if(mndis > w) 143 return ; 144 else if(mxdis <= w) 145 add(ID, id[u], 1); 146 else 147 dfs(p[u].ch[0], ID, o, w), 148 dfs(p[u].ch[1], ID, o, w); 149 } 150 void met_link(int x, int y, int w, int skid) { 151 int id = ++ cnt; 152 skill_id[cnt] = skid; 153 add(S, id, 1); 154 dfs(root, id, P(x, y), w); 155 } 156 } 157 int getthing(int u) { 158 if(thing_id[u]) return thing_id[u]; 159 for(int i = head[u] ; i ; i = rest[i]) { 160 int v = to[i]; 161 if(!(i & 1) && f[i ^ 1]) return -- f[i ^ 1], getthing(v); 162 } 163 assert(0); 164 return -1; 165 } 166 int main() { 167 n = read(), m = read(); 168 S = ++ cnt, T = ++ cnt; 169 for(int i = 1 ; i <= n ; ++ i) p[i].d[0] = read(), p[i].d[1] = read(), p[i].id = i; 170 KDT :: met_build(); 171 for(int i = 1, x, y, w ; i <= m ; ++ i) { 172 x = read(), y = read(), w = read(); 173 KDT :: met_link(x, y, w, i); 174 } 175 printf("%d\n", DINIC :: sol()); 176 for(int i = head[S] ; i ; i = rest[i]) { 177 int v = to[i]; 178 if(!(i & 1) && f[i ^ 1]) { 179 printf("%d %d\n", getthing(v), skill_id[v]); 180 } 181 } 182 }