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 }
ezoj 1235 [RYOI2018]榊野木乃实
posted @ 2018-09-01 17:55  KingSann  阅读(314)  评论(0编辑  收藏  举报