NOI前集训日志
持续更新。。
[Day1 2016-7-1]
水题赛被虐记
T1 cycle 求一个图中的负环,使它的点数最小 n <= 300
因为是求环,想一下O(n^3),floyd可以求最小环,可以倍增这个东西,先搞出来矩阵的2^n,再从大到小确定,如果这一位不乘便没有负环的话就必须要这一位
#define MAXN 310 #include <algorithm> #include <cstdio> using namespace std; const int inf = 1e9; int n, m; struct Node { int a[MAXN][MAXN]; void init() { for(int i = 1 ; i <= n ; ++ i) { for(int j = 1 ; j <= n ; ++ j) { a[i][j] = inf; } } } void print() { for(int i = 1 ; i <= n ; ++ i) { for(int j = 1 ; j <= n ; ++ j) { printf("%d ", a[i][j]); }puts(""); } } }mat[10], nw, tp; Node operator * (const Node& a, const Node& b) { Node ret; ret.init(); for(int i = 1 ; i <= n ; ++ i) for(int j = 1 ; j <= n ; ++ j) ret.a[i][j] = min(a.a[i][j], b.a[i][j]); for(int k = 1 ; k <= n ; ++ k) for(int i = 1 ; i <= n ; ++ i) for(int j = 1 ; j <= n ; ++ j) ret.a[i][j] = min(ret.a[i][j], a.a[i][k] + b.a[k][j]); return ret; } void cmin(int& a, int b) { if(a > b) a = b; } int main() { freopen("cycle.in", "r", stdin); freopen("cycle.out", "w", stdout); scanf("%d%d", &n, &m); int u, v, w, Mx = 1, lg = 0; mat[0].init(); for(; Mx<<1 <= n ; Mx<<=1, lg ++); for(int i = 1 ; i <= m ; ++ i) { scanf("%d%d%d", &u, &v, &w); cmin(mat[0].a[u][v], w); } for(int i = 1 ; i <= lg ; ++ i) mat[i] = mat[i-1] * mat[i-1]; //mat[lg].print(); int ans = 0; for(; Mx; Mx >>= 1, lg --) { tp = ans ? nw * mat[lg] : mat[lg]; bool fg = false; for(int i = 1 ; i <= n ; ++ i) if(tp.a[i][i] < 0){ fg = true; break; } if(fg) continue; nw = tp; ans ^= Mx; } if(ans < n)printf("%d\n", ans+1); else printf("0\n"); return 0; }
T2 road 给一个图,使得i与n-i+1联通,其中i<=d, d <= 4, d <= n / 2
复习了一下斯坦纳树,两个方程,1.斯坦纳树的两个子树合并,如果小于inf就放进队列中;2.向外延伸(spfa)
#define MAXN 100010 #include <cstdio> #include <queue> using namespace std; const int inf = 1e9; int n, m, d, ans = inf; int h[MAXN], cnt; struct Edge{int to, nxt, dis;}edge[MAXN]; void addedge(int u, int v, int d) { edge[++ cnt] = (Edge){v, h[u], d}; h[u] = cnt; edge[++ cnt] = (Edge){u, h[v], d}; h[v] = cnt; } int f[10010][256], dp[256], vis[MAXN]; queue<int> q; void spfa(int sta) { while(!q.empty()) { int u = q.front(); q.pop(); for(int i = h[u] ; i ; i = edge[i].nxt) { int v = edge[i].to; if(f[v][sta] > f[u][sta] + edge[i].dis) { f[v][sta] = f[u][sta] + edge[i].dis; if(!vis[v])q.push(v), vis[v] = true; } }vis[u] = false; } } int solve(int Max_s) { for(int i = 1 ; i <= n ; ++ i) for(int j = 0 ; j < Max_s ; ++ j) f[i][j] = inf; for(int i = 1 ; i <= d ; ++ i) { f[i][1<<i-1] = 0; f[n-i+1][1<<(i-1+d)] = 0; //printf("%d %d\n", 1<<i-1, 1<<(i-1+d)); } for(int sta = 0 ; sta < Max_s ; ++ sta) { //int x = sta >> d, y = sta & ((1<<d)-1); if(x != y) continue; for(int i = 1 ; i <= n ; ++ i) { for(int j = h[i]; j; j = edge[j].nxt) { int v = edge[j].to; for(int s = sta&(sta-1) ; s ; s = (s-1)&sta) f[i][sta] = min(f[i][sta], f[i][s] + f[v][sta^s] + edge[j].dis); } if(f[i][sta] != inf) q.push(i), vis[i] = 1; }spfa(sta); } } int main() { freopen("road.in", "r", stdin); freopen("road.out", "w", stdout); scanf("%d%d%d", &n, &m, &d); int u, v, w; for(int i = 1 ; i <= m ; ++ i) { scanf("%d%d%d", &u, &v, &w); addedge(u, v, w); } int S = 1 << (2*d); solve(S); dp[0] = 0; int T = 1 << d; for(int i = 1 ; i < T ; ++ i) { int to = i<<d|i, ret = inf; for(int j = 1 ; j <= n ; ++ j) ret = min(ret, f[j][to]); dp[to] = ret; } for(int i = 0 ; i < T ; ++ i) { int nw = i << d | i; for(int j = 0 ; j <= i ; ++ j) { if((i & j) != j) continue; int to = j << d | j; dp[nw] = min(dp[to] + dp[nw^to], dp[nw]); //if(i == 15)printf("%d %d\n", nw^to, to); } } //for(int i = 0 ; i < S ; ++ i)printf("dp[%d] = %d\n", i, dp[i]);puts(""); ans = dp[S-1]; if(ans != inf) printf("%d\n", ans); else puts("-1"); return 0; }
T3 network
给定一棵边权均为1 的无根树,点可能是黑色或白色,支持两种操作。
• 1 xi pi 表示目前点xi 的颜色可能发生了翻转(白变黑,黑变白),发生概率为pi%。
• 2 si 表示求E(( Σ(x=black, dist(x, si)) ) ^ 2)
这个平方就是一堆和相乘,这样把和分配给两项,每两两组合的a*b的sigma
我要求的答案就是p[i] * p[j] * dist(i, s) * dist(j, s) (p[i]为i是黑点的概率)
注意当i = j的时候,贡献是p[i] * dist(i, s) ^ 2, 因为p[i]代表i是黑点
那么我们要求的答案Ans = (Σp[i]*dist(i,s)) ^ 2 - Σp[i]^2 * dist(i, s)^2 + Σp[i] * dist(i, s)^2
用动态树分治做就可以了
#define MAXN 200010 #include <algorithm> #include <cstdio> using namespace std; const int inf = 1e9; int n, m, h[MAXN], cnt;; struct Edge { int to, nxt; }edge[MAXN<<1]; void addedge(int u, int v) { edge[++ cnt] = (Edge){v, h[u]}; h[u] = cnt; edge[++ cnt] = (Edge){u, h[v]}; h[v] = cnt; } //------------------------------------------------------------------------------------// int c[MAXN], fa[MAXN], dep[MAXN], st[MAXN][20], pos[MAXN], lg[MAXN], amt; inline int Min(int i, int j) { return dep[i] < dep[j] ? i : j; } void dfs(int u) { dep[u] = dep[fa[u]] + 1; st[++ amt][0] = u; pos[u] = amt; for(int i = h[u] ; i ; i = edge[i].nxt) { int v = edge[i].to; if(v == fa[u])continue; fa[v] = u; dfs(v); st[++ amt][0] = u; } } int ask_LCA(int p, int q) { p = pos[p], q = pos[q]; if(p > q)swap(p, q); int len = lg[q - p + 1]; return Min(st[p][len], st[q-(1<<len)+1][len]); } int dist(int x, int y) { return dep[x] + dep[y] - 2 * dep[ask_LCA(x, y)]; } //------------------------------------------------------------------------------------// int Mx, Sum, G, g[MAXN], size[MAXN]; double sum[MAXN], sp[MAXN], spp[MAXN], ppdd[MAXN], pdd[MAXN], ppd[MAXN], p[MAXN]; double _sum[MAXN], _sp[MAXN], _spp[MAXN], _ppdd[MAXN], _pdd[MAXN], _ppd[MAXN]; bool vis[MAXN]; void getg(int u, int fa) { int f = 0; size[u] = 1; for(int i = h[u] ; i ; i = edge[i].nxt) { int v = edge[i].to; if(v == fa || vis[v]) continue; getg(v, u); size[u] += size[v]; f = max(f, size[v]); } f = max(f, Sum - size[u]); if(f < Mx) { Mx = f, G = u; } } void work(int u, int f, int st) { int dis = dist(st, u); sp[st] += p[u]; spp[st] += p[u] * p[u]; sum[st] += p[u] * dis; pdd[st] += p[u] * dis * dis; ppd[st] += p[u] * p[u] * dis; ppdd[st] += p[u] * p[u] * dis * dis; for(int i = h[u] ; i ; i = edge[i].nxt) { int v = edge[i].to; if(v == f || vis[v]) continue; work(v, u, st); } } void work2(int u, int f, int st) { int dis = dist(g[st], u); _sp[st] += p[u]; _spp[st] += p[u] * p[u]; _sum[st] += p[u] * dis; _pdd[st] += p[u] * dis * dis; _ppd[st] += p[u] * p[u] * dis; _ppdd[st] += p[u] * p[u] * dis * dis; for(int i = h[u] ; i ; i = edge[i].nxt) { int v = edge[i].to; if(v == f || vis[v]) continue; work2(v, u, st); } } void solve(int u, int f) { g[u] = f; vis[u] = true; work(u, 0, u); if(f)work2(u, 0, u); for(int i = h[u] ; i ; i = edge[i].nxt) { int v = edge[i].to; if(vis[v]) continue; Mx = inf, Sum = size[v], G = v; getg(v, u), solve(G, u); } } //------------------------------------------------------------------------------------// int Standard; double Filp(int u, double x) { return p[u] * (1-x) + (1-p[u]) * x; } double sqr(double x) { return x * x; } void modify(int x, double w, double s) { int dis = dist(x, Standard); sp[x] += w; spp[x] += s; sum[x] += w * dis; ppd[x] += s * dis; pdd[x] += w * dis * dis; ppdd[x] += s * dis * dis; if(g[x] == 0) return; dis = dist(g[x], Standard); _sp[x] += w; _spp[x] += s; _sum[x] += w * dis; _ppd[x] += s * dis; _pdd[x] += w * dis * dis; _ppdd[x] += s * dis * dis; modify(g[x], w, s); } typedef pair<double, double> pii; pii ask(int x) { double dis = dist(x, Standard); double ret1 = sum[x]+dis*sp[x], ret2 = -(ppdd[x] + 2*ppd[x]*dis + spp[x]*sqr(dis)) + pdd[x] + 2*sum[x]*dis + sp[x]*sqr(dis); if(g[x] == 0) return make_pair(ret1, ret2); dis = dist(g[x], Standard); ret1 -= _sum[x]+dis*_sp[x], ret2 -= -(_ppdd[x] + 2*_ppd[x]*dis + _spp[x]*sqr(dis)) + _pdd[x] + 2*_sum[x]*dis + _sp[x]*sqr(dis); pii t = ask(g[x]); ret1 += t.first, ret2 += t.second; return make_pair(ret1, ret2); } int main() { freopen("network.in", "r", stdin); freopen("network.out", "w", stdout); scanf("%d", &n); scanf("%d%d", &n, &m); for(int i = 1 ; i <= n ; ++ i) scanf("%d", &c[i]), p[i] = c[i]; int u, v, w; for(int i = 1 ; i < n ; ++ i) { scanf("%d%d", &u, &v); addedge(u, v); } dfs(1); lg[0] = -1; for(int i = 1 ; i <= amt ; ++ i) lg[i] = lg[i>>1] + 1; for(int j = 1 ; 1<<j <= amt ; ++ j) for(int i = 1 ; i+(1<<j)-1 <= amt ; ++ i) st[i][j] = Min(st[i][j-1], st[i+(1<<j-1)][j-1]); Mx = inf, Sum = n; getg(1, 0); solve(G, 0); int tp; for(int i = 1; i <= m ; ++ i) { scanf("%d", &tp); if(tp == 1) { scanf("%d%d", &u, &w); double t = w / 100.0, k = Filp(u, t); Standard = u; modify(u, k-p[u], -p[u]*p[u]+k*k); p[u] = k; } else { scanf("%d", &u); Standard = u; pii t = ask(u) ; printf("%.10lf\n", sqr(t.first) + t.second); } } return 0; }
[Day4 2016-7-4]
T1:exercise
f[n] = (a*f[n-1] + b) / (c*f[n-1] + d) mod p
对于每组f0, n, a, b, c, d, p(p 是质数),求fn。
保证除法时逆元一定存在。
暴力搞出相邻三项的式子,发现它的系数是
|A C|
|B D|
这个矩阵的平方
然后快速幂就好了。。
#include <cstdio> using namespace std; typedef long long ll; int a, b, c, d, f0, md; ll n; struct Matrix { int a[2][2]; void clr() { a[0][0] = a[0][1] = a[1][0] = a[1][1] = 0; } void set() { clr(); a[0][0] = a[1][1] = 1; } }nw, ret; Matrix operator * (const Matrix& a, const Matrix& b) { Matrix c; for(int i = 0 ; i < 2 ; ++ i) for(int j = 0 ; j < 2 ; ++ j) c.a[i][j] = ((ll)a.a[i][0]*b.a[0][j] + (ll)a.a[i][1]*b.a[1][j]) % md; return c; } ll power_mod(ll a, ll b) { ll ret = 1; while(b > 0) { if(b & 1) ret = ret * a % md; b >>= 1; a = a * a % md; } return ret; } int solve() { nw.a[0][0] = a, nw.a[1][0] = b; nw.a[0][1] = c, nw.a[1][1] = d; ret.set(); while(n > 0) { if(n & 1) ret = ret * nw; n >>= 1; nw = nw * nw; } ll f = ((ll)f0 * ret.a[0][0] + ret.a[1][0]) % md; ll g = ((ll)f0 * ret.a[0][1] + ret.a[1][1]) % md; f = (ll) f * power_mod(g, md-2) % md; return f; } int main() { freopen("exercise.in", "r", stdin); freopen("exercise.out", "w", stdout); int test; scanf("%d", &test); while(test --) { scanf("%d%d%d%d%d%lld%d", &f0, &a, &b, &c, &d, &n, &md); if(a < 0) a += md; if(b < 0) b += md; if(c < 0) c += md; if(d < 0) d += md; printf("%d\n", solve()); } return 0; }
T2:mountain
pty爬山
求爬过的节点数目
题解在2013年论文集
#define MAXN 1000010 #include <algorithm> #include <cstdio> using namespace std; typedef long long ll; struct Point { int x, y, i; }; Point operator - (const Point& a, const Point& b) { return (Point){a.x-b.x, a.y-b.y}; } ll operator ^ (const Point& a, const Point& b) { return (ll)a.x*b.y-(ll)a.y*b.x; } Point a[MAXN], lw[MAXN], rw[MAXN], h[MAXN]; int n, fa[MAXN], tot, Lt[MAXN], Rt[MAXN], tmp[MAXN]; ll f[MAXN]; struct arr { int v, t; bool operator < (const arr& k) const { return v < k.v || (v == k.v && (t&1) < (k.t&1)) || (v == k.v && (t&1) == (k.t&1) && t < k.t); } }p[MAXN]; ll abs(ll x) { return x > 0 ? x : -x; } void init() { scanf("%d", &n); for(int i = 1 ; i <= n ; ++ i) scanf("%d%d", &a[i].x, &a[i].y), a[i].i = i; } void find(int u) { tot = 0; while(fa[u]) tmp[++ tot] = u, u = fa[u]; for(int i = tot ; i >= 1 ; -- i) { int u = tmp[i]; f[u] = f[fa[u]] + abs(fa[u]-u); fa[u] = 0; } return; } void make_ans() { for(int i = 1 ; i <= n ; ++ i) if(fa[i]) find(i); for(int i = 1 ; i <= n ; ++ i) printf("%lld\n", f[i]); } void work() { tot = 0; for(int i = 1 ; i <= n ; ++ i) { while(tot > 0 && ((h[tot]-h[tot-1])^(a[i]-h[tot-1])) >= 0) tot --; lw[i] = h[tot]; if(i == 1 || a[i].y >= lw[i].y) lw[i] = a[i]; h[++ tot] = a[i]; } tot = 0; for(int i = n ; i >= 1 ; -- i){ while(tot > 1 && ((h[tot]-h[tot-1])^(a[i]-h[tot-1])) <= 0) tot --; rw[i] = h[tot]; if(i == n || a[i].y > rw[i].y) rw[i] = a[i]; h[++ tot] = a[i]; } for(int i = 1 ; i <= n ; ++ i) { if(lw[i].y > rw[i].y) p[i].v = lw[i].y, p[i].t = i<<1; else p[i].v = rw[i].y, p[i].t = i<<1|1; } sort(p+1, p+1+n); for(int i = 1 ; i <= n ; ++ i) Lt[i] = i-1, Rt[i] = i+1; for(int i = 1 ; i <= n ; ++ i) { int j = p[i].t >> 1; if(p[i].t & 1) fa[j] = Rt[j]; else fa[j] = Lt[j]; Rt[Lt[j]] = Rt[j]; Lt[Rt[j]] = Lt[j]; } fa[p[n].t>>1] = 0; make_ans(); } int main() { freopen("mountain.in", "r", stdin); freopen("mountain.out", "w", stdout); init(); work(); return 0; }
r,c<=n,m<=1000. k <= n*m
神题。。把平方拆开还有一个矩阵与矩阵的乘法
用二维卷积
#define MAXN 1010 #define MAXM 2200000 #include <algorithm> #include <cstdio> #include <cmath> using namespace std; typedef long long ll; typedef long double ld; const ld pi = 3.1415926535897932384626433832795; const int md = 998244353, G = 3; struct Point { ll val; int i, j; }; bool operator < (const Point& a, const Point& b) { if(a.val != b.val)return a.val < b.val; if(a.i != b.i) return a.i < b.i; return a.j < b.j; } /* struct cpx { ld r, i; }; cpx operator + (const cpx& a, const cpx& b) { return (cpx){a.r+b.r, a.i+b.i}; } cpx operator - (const cpx& a, const cpx& b) { return (cpx){a.r-b.r, a.i-b.i}; } cpx operator * (const cpx& a, const cpx& b) { return (cpx){a.r*b.r-a.i*b.i, a.r*b.i+a.i*b.r}; } cpx operator / (const cpx& a, const ld& k) { return (cpx){a.r/k, a.i/k}; } cpx f[MAXM], g[MAXM]; void fft(cpx A[], int n, int tp) { for(int i = 0, j = 0 ; i < n ; ++ i) { if(i > j) swap(A[i], A[j]); for(int t = n>>1 ; (j^=t) < t ; t >>= 1); } for(int k = 2 ; k <= n ; k <<= 1) { int t = k>>1; cpx wn = (cpx){cos(2*pi/k), tp*sin(2*pi/k)}; for(int i = 0 ; i < n ; i += k) { cpx w = (cpx){1, 0}; for(int j = 0 ; j < t ; ++ j) { cpx T = w * A[i+j+t]; A[i+j+t] = A[i+j] - T; A[i+j] = A[i+j] + T; w = w * wn; } } } if(tp == -1) { for(int i = 0 ; i < n ; ++ i) A[i] = A[i] / n; } } */ int f[MAXM], g[MAXM]; Point nw[MAXM]; int n, m, r, c, A[MAXN][MAXN], B[MAXN][MAXN], C[MAXN][MAXN]; ll s[MAXN][MAXN], SA[MAXN][MAXN], SB, S[MAXN][MAXN], Sb; ll sqr(ll a) { return a * a; } ll square_SA(int x1, int y1, int x2, int y2) { x1 --, y1 --; ll ret = SA[x2][y2]; if(x1 >= 0) ret -= SA[x1][y2]; if(y1 >= 0) ret -= SA[x2][y1]; if(x1 >= 0 && y1 >= 0) ret += SA[x1][y1]; return ret; } ll square_S(int x1, int y1, int x2, int y2) { x1 --, y1 --; ll ret = S[x2][y2]; if(x1 >= 0) ret -= S[x1][y2]; if(y1 >= 0) ret -= S[x2][y1]; if(x1 >= 0 && y1 >= 0) ret += S[x1][y1]; return ret; } int power_mod(int a, int b = md-2) { int ret = 1; while(b > 0) { if(b & 1)ret = (ll)ret * a % md; b >>= 1; a = (ll)a * a % md; } return ret; } void ntt(int A[], int n, int tp) { for(int i = 0 ; i < n ; ++ i) if(A[i] < 0) A[i] += md; for(int i = 0, j = 0 ; i < n ; ++ i) { if(i > j) swap(A[i], A[j]); for(int t = n>>1 ; (j^=t) < t ; t >>= 1); } for(int k = 2 ; k <= n ; k <<= 1) { int t = k>>1; int wn = power_mod(G, tp > 0 ? (md-1)/k : (md-1)-(md-1)/k); for(int i = 0 ; i < n ; i += k) { int w = 1; for(int j = 0 ; j < t ; ++ j) { int T = (ll)w * A[i+j+t] % md; A[i+j+t] = A[i+j] - T; if(A[i+j+t]<0) A[i+j+t] += md; A[i+j] = A[i+j] + T; if(A[i+j] >= md) A[i+j] -= md; w = (ll)w * wn % md; } } } if(tp == -1) { ll inv = power_mod(n); for(int i = 0 ; i < n ; ++ i) { A[i] = (ll)A[i] * inv % md; if(A[i] < 0) A[i] += md; } } } int main() { freopen("matrix.in", "r", stdin); freopen("matrix.out", "w", stdout); scanf("%d%d", &n, &m); for(int i = 0 ; i < n ; ++ i) for(int j = 0 ; j < m ; ++ j) scanf("%d", &A[i][j]); scanf("%d%d", &r, &c); for(int i = 0 ; i < r ; ++ i) for(int j = 0 ; j < c ; ++ j) scanf("%d", &C[i][j]); for(int i = 0 ; i < n ; ++ i) for(int j = 0 ; j < m ; ++ j) B[i][j] = C[n-i-1][m-j-1]; /* int cnt = 0, N; for(int i = 0 ; i < n ; ++ i) for(int j = 0 ; j < m ; ++ j) f[cnt ++] = (cpx){A[i][j], 0}; cnt = 0; for(int i = 0 ; i < n ; ++ i) for(int j = 0 ; j < m ; ++ j) g[cnt ++] = (cpx){B[i][j], 0}; for(N = 1 ; N <= cnt+cnt ; N <<= 1); fft(f, N, 1); fft(g, N, 1); for(int i = 0 ; i < N ; ++ i) f[i] = f[i] * g[i]; fft(f, N, -1); */ int cnt = 0, N; for(int i = 0 ; i < n ; ++ i) for(int j = 0 ; j < m ; ++ j) f[cnt ++] = A[i][j]; cnt = 0; for(int i = 0 ; i < n ; ++ i) for(int j = 0 ; j < m ; ++ j) g[cnt ++] = B[i][j]; for(N = 1 ; N <= cnt+cnt ; N <<= 1); ntt(f, N, 1); ntt(g, N, 1); for(int i = 0 ; i < N ; ++ i) f[i] = (ll)f[i] * g[i] % md; ntt(f, N, -1); int inf = 30*1000*1000; for(int i = 0 ; i < n ; ++ i) for(int j = 0 ; j < m ; ++ j) { s[i][j] = f[n*m+i*m+j-1]; if(s[i][j] > inf) s[i][j] -= md; } int dx, dy, k; scanf("%d%d%d", &dx, &dy, &k); S[0][0] = A[0][0]; SA[0][0] = sqr(A[0][0]); for(int i = 1 ; i < n ; ++ i) { S[i][0] = S[i-1][0] + A[i][0]; SA[i][0] = SA[i-1][0] + sqr(A[i][0]); } for(int i = 1 ; i < m ; ++ i) { S[0][i] = S[0][i-1] + A[0][i]; SA[0][i] = SA[0][i-1] + sqr(A[0][i]); } for(int i = 1 ; i < n ; ++ i) for(int j = 1 ; j < m ; ++ j) { S[i][j] = S[i][j-1] + S[i-1][j] - S[i-1][j-1] + A[i][j]; SA[i][j] = SA[i][j-1] + SA[i-1][j] - SA[i-1][j-1] + sqr(A[i][j]); } for(int i = 0 ; i < r ; ++ i) for(int j = 0 ; j < c ; ++ j) SB += sqr(C[i][j]), Sb += C[i][j]; int num = r * c; cnt = 0; for(int i = 0 ; i <= n-r ; ++ i) for(int j = 0 ; j <= m-c ; ++ j) { int to = A[i+dx-1][j+dy-1]; nw[++ cnt] = (Point){square_SA(i, j, i+r-1, j+c-1) + SB + num*sqr(to) - 2*s[i][j] - 2*square_S(i, j, i+r-1, j+c-1)*to + 2*Sb*to, i+1, j+1}; } sort(nw+1, nw+1+cnt); for(int i = 1 ; i <= k ; ++ i) printf("%d %d %lld\n", nw[i].i, nw[i].j, nw[i].val); return 0; }
[2016-7-16] 存在了网易网盘集训交流文件夹下
1.snow
太沙茶了竟然写错了链表。。
挺好的一道题,很多神犇都用线段树写的
我写了堆+线段树+链表
#define MAXN 300010 #include <algorithm> #include <cstdio> #include <queue> using namespace std; int m, n, pre[MAXN], nxt[MAXN], f[MAXN]; struct Seg { int l, r; } p[MAXN], ret1, ret2, tmp; bool operator < (const Seg& a, const Seg& b) { return a.l < b.l; } bool cmp(int i, int j) { return p[i].l < p[j].l; } struct Node{ int len, l, r, id; } nw; bool operator < (const Node& a, const Node& b) { if(a.len != b.len)return a.len > b.len; return a.id > b.id; } priority_queue<Node> q; bool vis[MAXN]; int mx[MAXN<<2], mn[MAXN<<2]; #define lc id<<1 #define rc id<<1|1 void build(int id, int l, int r) { if(l == r) { mn[id] = p[l].l; mx[id] = p[l].r; return; } int mid = l + r >> 1; build(lc, l, mid); build(rc, mid+1, r); mn[id] = mn[lc]; mx[id] = mx[rc]; } void pushdown(int id) { mn[lc] = max(mn[lc], mn[id]); mx[lc] = min(mx[lc], mx[id]); mn[rc] = max(mn[rc], mn[id]); mx[rc] = min(mx[rc], mx[id]); } void upd1(int id, int l, int r, int p, int v) { if(r <= p) { mx[id] = min(mx[id], v); return; } pushdown(id); int mid = l + r >> 1; if(p <= mid) upd1(lc, l, mid, p, v); else { mx[lc] = min(mx[lc], v); upd1(rc, mid+1, r, p, v); } } void upd2(int id, int l, int r, int p, int v) { if(l >= p) { mn[id] = max(mn[id], v); return; } pushdown(id); int mid = l + r >> 1; if(p <= mid) { mn[rc] = max(mn[rc], v); upd2(lc, l, mid, p, v); } else upd2(rc, mid+1, r, p, v); } Seg ask(int id, int l, int r, int p) { if(l == r) return (Seg){mn[id], mx[id]}; pushdown(id); int mid = l + r >> 1; if(p <= mid) return ask(lc, l, mid, p); else return ask(rc, mid+1, r, p); } void Delete() { if(nw.id != 1) upd1(1, 1, n, nw.id-1, nw.l); if(nw.id != n) upd2(1, 1, n, nw.id+1, nw.r); int pr = pre[nw.id], nt = nxt[nw.id]; if(nt) pre[nt] = pr, ret2 = ask(1, 1, n, nt); if(pr) { nxt[pr] = nt, ret1 = ask(1, 1, n, pr); while(pre[pr]) { tmp = ask(1, 1, n, pre[pr]); if(tmp.l == ret1.l && tmp.r == ret1.r) { // q.push((Node){ret1.r-ret1.l, ret1.l, ret1.r, pr}); pr = pre[pr], ret1 = tmp; } else break; } } if(!pr && !nt) return; if(pr && nt) { q.push((Node){ret1.r-ret1.l, ret1.l, ret1.r, pr}); q.push((Node){ret2.r-ret2.l, ret2.l, ret2.r, nt}); } else if(pr) q.push((Node){ret1.r-ret1.l, ret1.l, ret1.r, pr}); else if(nt) q.push((Node){ret2.r-ret2.l, ret2.l, ret2.r, nt}); } int main() { freopen("snow.in", "r", stdin); freopen("snow.out", "w", stdout); scanf("%d%d", &m, &n); for(int i = 1; i <= n; ++ i) { scanf("%d%d", &p[i].l, &p[i].r); f[i] = i; } sort(f+1, f+1+n, cmp); for(int i = 1; i <= n; ++ i) pre[i] = i-1, nxt[i] = i+1; nxt[n] = 0; sort(p+1, p+1+n); build(1, 1, n); for(int i = 1; i <= n; ++ i) q.push((Node){p[i].r-p[i].l, p[i].l, p[i].r, i}); while(!q.empty()) { nw = q.top(); q.pop(); if(vis[nw.id]) continue; vis[nw.id] = true; printf("%d\n", f[nw.id]); Delete(); } return 0; }