@Falsyta
2015-10-24T12:39:31.000000Z
字数 8622
阅读 1672
OI
AMPPZ
虽然暂时没写完但是为了增加填坑动力还是单挂出来好了。
由于起点终点都是加油站可以只考虑加油站。
建超级源点跑最短路,考虑离每个点最近的加油站。
容易发现一个加油站
然后建出只含加油站的新图以后就转化成每次询问路径边权最小值。
# include <cstdio>
# include <algorithm>
# define REP(i, n) for (int i = 1; i <= n; ++ i)
# define REP_G(i, x) for (int i = pos[x]; i; i = g[i].frt)
using namespace std;
const int inf = 1 << 30;
# define NR 201000
struct Edge {int y, frt, val; void set (int _y, int _frt, int _val) {y = _y, frt = _frt, val = _val;}} g[NR << 1];
struct Arr {int x, y, w, id; Arr () {x = y = w = id = 0;} Arr (int _x, int _y, int _w, int _id): x(_x), y(_y), w(_w), id(_id) {}} e[NR << 1], qy[NR];
int n, s, m, gsz, id[NR], q[5001000], fa[NR], pos[NR], dt[NR], esz, q0, ans[NR];
bool inq[NR];
# define v g[i].y
inline bool cmpE (Arr a, Arr b) {return a.w < b.w;}
inline void AE (int x, int y, int z) {g[++ gsz].set (y, pos[x], z), pos[x] = gsz;}
inline int gf (int x) {return fa[x] == x ? x : (fa[x] = gf (fa[x]));}
void spfa ()
{
int head = 1, tail = 0, x;
REP (i, n) id[i] ? inq[q[++ tail] = i] = true : dt[i] = inf;
while (head <= tail)
{
x = q[head ++];
REP_G (i, x)
if (dt[x] + g[i].val < dt[v])
{
dt[v] = dt[x] + g[i].val, id[v] = id[x];
if (!inq[v]) inq[q[++ tail] = v] = true;
}
inq[x] = false;
}
}
int main ()
{
scanf ("%d%d%d", &n, &s, &m); int t1, t2, t3;
REP (i, s) scanf ("%d", &t1), id[t1] = t1;
REP (i, m) scanf ("%d%d%d", &t1, &t2, &t3), AE (t1, t2, t3), AE (t2, t1, t3);
spfa ();
REP (x, n) {REP_G (i, x) if (id[x] < id[v]) e[++ esz] = Arr (id[x], id[v], dt[x] + dt[v] + g[i].val, 0); fa[x] = x;}
sort (e + 1, e + esz + 1, cmpE), scanf ("%d", &q0);
REP (i, q0) scanf ("%d%d%d", &qy[i].x, &qy[i].y, &qy[i].w), qy[i].id = i;
sort (qy + 1, qy + q0 + 1, cmpE);
int j = 1;
REP (i, q0)
{
for (; j <= esz && e[j].w <= qy[i].w; ++ j) {int fx = gf (e[j].x), fy = gf (e[j].y); if (fx != fy) fa[fx] = fy;}
ans[qy[i].id] = gf (qy[i].x) == gf (qy[i].y);
}
REP (i, q0) puts (ans[i] ? "TAK" : "NIE");
return 0;
}
感觉自己简直在凑数……
本来想用FWT发现没有暴力快……
复杂度
# include <cstdio>
# include <algorithm>
using namespace std;
# define REP(i, n) for (int i = 1; i <= n; ++ i)
# define REP_0(i, n) for (int i = 0; i < n; ++ i)
# define SR (1 << 16)
# define NR 20
const int inf = 1 << 30;
int n, m, fi[SR], ts[SR], ans[SR], bid[SR], a[NR];
int main ()
{
scanf ("%d%d", &n, &m);
int M = 1 << m;
REP_0 (i, m) bid[1 << i] = i;
REP_0 (i, M) fi[i] = inf;
REP (i, n)
{
scanf ("%d", &ts[0]);
REP_0 (j, m) scanf ("%d", &a[j]);
REP (s, M - 1) ts[s] = ts[s ^ (s & -s)] + a[bid[s & -s]], fi[s] = min (fi[s], ts[s]);
}
REP (i, M - 1)
{
ans[i] = fi[i];
for (int j = (i - 1) & i; j; j = (j - 1) & i) ans[i] = min (ans[i], ans[j] + ans[i - j]);
}
printf ("%d\n", ans[M - 1]);
return 0;
}
之前没看见限制……那个破翻译什么玩意啊T_T
有了限制就见了障碍就绕行就行了……
# include <cstdio>
# include <algorithm>
# define REP(i, n) for (int i = 1; i <= n; ++ i)
# define pc putchar
using namespace std;
# define NR 1010
int p[NR], n, m, K;
bool a[NR][NR], fil[NR];
void ret (int x, int y)
{
a[x][y] = true;
if (x == 2 && y == 1) {pc ('D'); return ;}
if (!fil[x]) {pc ('D'), ret (x - 1, y); return ;}
if (y == 1) pc ('P'), fil[x] = false, ret (x, y + 1);
else pc ('L'), fil[x] = false, ret (x, y - 1);
}
void dfs (int x, int y)
{
a[x][y] = true;
if (x == 2 && y == 1) {pc ('D'); return ;}
if (x > 1 && !a[x - 1][y])
{
if (y == 2) for (int i = x - 1; i >= 1 && !a[i][y]; -- i) a[i][y] = fil[i] = true;
else {pc ('D'), dfs (x - 1, y); return ;}
}
int _x = x, _y = x % 2 ? y + 1 : y - 1;
if (_y == 1)
{
if (x == n) {pc ('L'); ret (_x, _y); return ;}
pc ('G'), dfs (x + 1, y); return ;
}
if (_y == m + 1) {pc ('G'), dfs (x + 1, y); return ;}
if (a[_x][_y]) {pc ('G'), dfs (x + 1, y); return ;}
x % 2 ? pc ('P') : pc ('L');
dfs (_x, _y);
}
int main ()
{
scanf ("%d%d%d", &n, &m, &K); int t1, t2;
swap (n, m);
REP (i, K) scanf ("%d%d", &t1, &t2), swap (t1, t2), a[t1][t2] = a[t1 + 1][t2] = a[t1][t2 + 1] = a[t1 + 1][t2 + 1] = true;
puts ("TAK");
dfs (1, 1);
return 0;
}
『我说啊,弱智是天生的么?』
枚举最小值
# include <cstdio>
# include <algorithm>
using namespace std;
# define REP(i, n) for (int i = 1; i <= n; ++ i)
# define REP_D(i, n) for (int i = n; i >= 1; -- i)
# define NR 501000
int n, a[NR], pl[NR], pr[NR], ml[NR], mr[NR], il[NR], ir[NR], ql[NR], qr[NR];
const int inf = 1 << 30;
pair <int, int> ans;
template <class T0, class T1> bool RlxN (T0 &x, T1 y) {if (x > y) return x = y, true; return false;}
template <class T0, class T1> bool RlxX (T0 &x, T1 y) {if (x < y) return x = y, true; return false;}
int main ()
{
scanf ("%d", &n);
pl[1] = ql[1] = 0, pr[n] = qr[n] = n + 1, ans = make_pair (-1, 1);
REP (i, n) ml[i] = mr[i] = -inf;
REP (i, n)
{
scanf ("%d", &a[i]);
if (i == 1) continue;
int j;
for (j = i - 1; j > 0 && a[j] > a[i]; j = pl[j])
{
if (a[j] > ml[i]) ml[i] = a[j], il[i] = j;
if (ml[j] > ml[i]) ml[i] = ml[j], il[i] = il[j];
}
pl[i] = j;
for (j = i - 1; j > 0 && a[j] < a[i]; j = ql[j]) ;
ql[i] = j;
}
REP_D (i, n - 1)
{
int j;
for (j = i + 1; j <= n && a[j] > a[i]; j = pr[j])
{
if (a[j] > mr[i]) mr[i] = a[j], ir[i] = j;
if (mr[j] > mr[i]) mr[i] = mr[j], ir[i] = ir[j];
}
pr[i] = j;
for (j = i + 1; j <= n && a[j] < a[i]; j = qr[j]) ;
qr[i] = j;
}
REP (i, n)
{
int l0, l1, r0, r1;
if (ml[i] != mr[i]) ml[i] < mr[i] ? ml[i] = -inf : mr[i] = -inf;
l0 = l1 = pl[i] + 1, r0 = r1 = pr[i] - 1;
if (ml[i] != -inf) RlxX (l0, il[i] + 1), RlxX (l1, ql[il[i]] + 1);
if (mr[i] != -inf) RlxN (r0, ir[i] - 1), RlxN (r1, qr[ir[i]] - 1);
RlxN (ans, make_pair (-(r1 - l0 + 1), l0));
RlxN (ans, make_pair (-(r0 - l1 + 1), l1));
}
printf ("%d %d\n", -ans.first, ans.second);
return 0;
}
题目愣是看错了两次想了三天T_T
直接导致自己毫无输出……(明明是自己的错啦……
去掉怨念以后题目还凑活吧。
枚举答案,显然只剩下
然后我们暴力枚举每个星号的状态,然后通过看出现位置之间的间隔是否超过答案来判定。
每个出现位置能匹配的状态数应该是
于是做一次的复杂度感觉是
应该就能过了……
# include <cstdio>
# include <cstring>
# define REP(i, n) for (int i = 1; i <= n; ++ i)
# define NR 3010
int q0, n, li[NR], lu[NR], lt[NR], len, m, lcp[NR], z, unk[NR][30];
char s[NR], tmp[NR][30], a[NR], d[30];
inline bool ec (char a, char b) {return a == b || a == '*' || b == '*';}
bool check ()
{
int last = 0;
REP (i, len)
{
if (li[i] - last > z) return false;
bool eql = true; REP (j, m) if (!ec (tmp[i][j], d[j])) {eql = false; break;}
if (eql) last = li[i];
}
return true;
}
bool dfs (int lv)
{
if (lv > m) return check ();
d[lv] = 'R'; if (dfs (lv + 1)) return true;
d[lv] = 'G'; if (dfs (lv + 1)) return true;
d[lv] = 'B'; return dfs (lv + 1);
}
int main ()
{
for (scanf ("%d", &q0); q0; -- q0)
{
scanf ("%s", s + 1), n = strlen (s + 1);
REP (i, n)
{
int j = 0; lu[i] = 0;
for (; i + j <= n && ec (s[1 + j], s[i + j]); ++ j)
if (s[1 + j] == '*') unk[i][++ lu[i]] = i + j;
lcp[i] = j;
}
bool succ = false;
for (z = 1; z < n; ++ z)
{
int last = 0, t = n - z + 1; bool fail = false;
if (lcp[t] < z) continue;
m = len = 0;
REP (i, z) {a[i] = s[i]; if (a[i] == '*') a[i] = s[n - z + i], m += s[n - z + i] == '*';}
REP (i, n - z + 1)
{
if (i - last > z) {fail = true; break;}
if (lcp[i] < z) continue;
bool eql = true;
REP (j, lu[t]) if (!ec (s[unk[i][j]], s[unk[t][j]])) {eql = false; break;}
if (eql)
{
li[++ len] = last = i; lt[len] = 0;
REP (j, lu[t]) if (s[unk[t][j]] == '*') tmp[len][++ lt[len]] = s[unk[i][j]];
}
}
if (fail) continue;
if (dfs (1))
{
int j = 0;
REP (i, z) putchar (a[i] == '*' ? d[++ j] : a[i]);
succ = true; break;
}
}
if (!succ) REP (i, n) putchar (s[i] == '*' ? 'R' : s[i]);
putchar ('\n');
}
return 0;
}
考虑拆环后用线段树维护。
对于一个区间考虑头的状态对整个区间的影响。
注意到最先开枪的后一个人的状态是确定的。
# include <cstdio>
# include <cstdlib>
# include <algorithm>
# include <vector>
using namespace std;
# define REP(i, n) for (int i = 1; i <= n; ++ i)
# define REP_0(i, n) for (int i = 0; i < n; ++ i)
# define REP_V(it, s) for (vector <int>::iterator it = s.begin (); it != s.end (); ++ it)
# define NR 201000
typedef pair <int, int> Pii;
typedef int Arr[3];
Pii ap[NR];
int ti[NR], tp[NR], ans[NR], n, q0, csz;
struct Info
{
Pii min; int s[3], c[3];
Info () {min = make_pair (0, 0), s[0] = s[1] = s[2] = c[0] = c[1] = c[2] = 0;}
Info (Pii _min, int _s0, int _s1, int _s2, int _c0, int _c1, int _c2)
{min = _min, s[0] = _s0, s[1] = _s1, s[2] = _s2, c[0] = _c0, c[1] = _c1, c[2] = _c2;}
};
# define NEXT_S(t) next[p][a.s[t]]
# define u t[x]
# define lc ch[0]
# define rc ch[1]
# define ulfc t[u.lc]
# define urtc t[u.rc]
# define w0 first
# define w1 second
struct Seg
{
int ch[2]; Info w;
inline void init (Pii min) {w.min = min, w.s[0] = 0, w.s[1] = 1, w.s[2] = 2, w.c[0] = 0, w.c[1] = 0, w.c[2] = 1;}
};
struct SegTree
{
Seg *t;
Arr *next;
vector <int> id;
int root, sz, n, N;
Info merge (const Info &a, const Info &b, int p)
{
return p %= n, Info (min (a.min, b.min),
b.s[NEXT_S (0)], b.s[NEXT_S (1)], b.s[NEXT_S (2)],
a.c[0] + b.c[NEXT_S (0)], a.c[1] + b.c[NEXT_S (1)], a.c[2] + b.c[NEXT_S (2)]);
}
int build (int l, int r)
{
int x = ++ sz, mid = (l + r) >> 1;
if (l == r) return u.init (make_pair (ti[id[l % n]], l)), x;
return u.lc = build (l, mid), u.rc = build (mid + 1, r), u.w = merge (ulfc.w, urtc.w, mid), x;
}
void segUpd (int x, int l, int r, int p)
{
if (l == r) {u.w.min = make_pair (ti[id[l % n]], l); return ;}
int mid = (l + r) >> 1;
if (p <= mid) segUpd (u.lc, l, mid, p);
else segUpd (u.rc, mid + 1, r, p);
u.w = merge (ulfc.w, urtc.w, mid);
}
Info segQry (int x, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr) return u.w;
int mid = (l + r) >> 1;
if (qr <= mid) return segQry (u.lc, l, mid, ql, qr);
if (ql > mid) return segQry (u.rc, mid + 1, r, ql, qr);
return merge (segQry (u.lc, l, mid, ql, qr), segQry (u.rc, mid + 1, r, ql, qr), mid);
}
inline int getAns () {int p = t[root].w.min.w1; return segQry (root, 0, N, (p + 1) % n, (p + 1) % n + n - 1).c[0];}
inline int update (int r)
{
next[r][1] = next[r][2] = (ti[id[r % n]] > ti[id[(r + 1) % n]]);
int l = (r + n - 1) % n;
next[l][1] = next[l][2] = (ti[id[l % n]] > ti[id[(l + 1) % n]]);
return segUpd (root, 0, N, l), segUpd (root, 0, N, r), segUpd (root, 0, N, l + n), segUpd (root, 0, N, r + n), getAns ();
}
inline int init ()
{
n = id.size (), N = 2 * n - 1;
t = (Seg*) malloc ((4 * n + 10) * sizeof (Seg));
next = (Arr*) malloc ((n + 10) * sizeof (Arr));
REP_0 (i, n) ap[id[i % n]].w1 = i % n, next[i][0] = 2, next[i][1] = next[i][2] = (ti[id[i % n]] > ti[id[(i + 1) % n]]);
return root = build (0, N), getAns ();
}
} sol[NR];
int main ()
{
scanf ("%d", &n); int sum = 0, t1, t2;
REP (i, n) scanf ("%d", &tp[i]);
REP (i, n) scanf ("%d", &ti[i]);
REP (i, n)
{
if (ap[i].w0) continue;
ap[i].w0 = ++ csz, sol[csz].id.clear (), sol[csz].id.push_back (i);
for (int j = tp[i]; j != i; j = tp[j]) sol[csz].id.push_back (j), ap[j].w0 = csz;
sum += (ans[csz] = sol[csz].init ());
}
printf ("%d\n", sum);
scanf ("%d", &q0);
REP (i, q0)
{
scanf ("%d%d", &t1, &t2), ti[t1] = t2;
int ts = ans[ap[t1].w0];
printf ("%d\n", sum += (ans[ap[t1].w0] = sol[ap[t1].w0].update (ap[t1].w1)) - ts);
}
return 0;
}