省选测试46
又倒第一了,流汗黄豆稳了
A 签到题
题目大意 : 每个点有个到最后的单调栈,会有修改和询问
-
转换一下题意,找到后面第一个比自己大的点向自己连边,就形成了个森林,建个超级源点,就成了颗树
-
修改操作就变成了把x和x的一级儿子都加上v,询问操作变成了查找x,y路径上的和,如果x,y的lca是x或y,那么还要再加上fa[lca]的值
-
询问好搞,树剖就行,问题是如何修改x和x的所有儿子。由于有树剖,可以考虑只修改x和x的重儿子,给x记一个标记,然后跳轻边的时候加上fa[tp]的标记
-
最后一条链如果链顶是tp的话,还得加上fa[tp]的标记,lca是xy的要特殊处理一下
Code
Show Code
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
return x * f;
}
struct Edge {
int n, t;
}e[N];
int h[N], edc;
void Add(int x, int y) {
e[++edc] = (Edge) {h[x], y}; h[x] = edc;
}
ll t[N], s[N], ans;
int n, m, a[N], stk[N], top, dep[N], sz[N], son[N], fa[N], tp[N], dfn[N], dfc;
void Dfs(int x) {
dep[x] = dep[fa[x]] + 1; sz[x] = 1;
for (int i = h[x], y; i; i = e[i].n) {
if ((y = e[i].t) == fa[x]) continue;
fa[y] = x; Dfs(y); sz[x] += sz[y];
if (sz[son[x]] < sz[y]) son[x] = y;
}
}
void Dfs(int x, int top) {
tp[x] = top; dfn[x] = ++dfc;
if (son[x]) Dfs(son[x], top);
for (int i = h[x], y; i; i = e[i].n)
if ((y = e[i].t) != fa[x] && y != son[x]) Dfs(y, y);
}
void Modify(int x, int w) {
for (; x <= dfc; x += x & -x) t[x] += w;
}
ll Ask(int l, int r, ll ans = 0) {
for (; r; r -= r & -r) ans += t[r];
for (l--; l; l -= l & -l) ans -= t[l];
return ans;
}
int main() {
freopen("set.in", "r", stdin);
freopen("set.out", "w", stdout);
n = read(); m = read();
for (int i = 1; i <= n; ++i)
a[i] = read();
stk[++top] = n + 1; a[n+1] = 1e9;
for (int i = n; i >= 1; --i) {
while (top && a[i] >= a[stk[top]]) top--;
Add(stk[top], i); stk[++top] = i;
}
Dfs(n + 1); Dfs(n + 1, n + 1);
for (int i = 1; i <= n; ++i)
Modify(dfn[i], read());
while (m--) {
int od = read(), x = read(), y = read(); ans = 0;
if (od == 1) {
Modify(dfn[x], y); s[x] += y;
if (son[x]) Modify(dfn[son[x]], y);
}
else {
int tmp = dep[x] < dep[y] ? x : y;
while (tp[x] != tp[y]) {
if (dep[tp[x]] < dep[tp[y]]) swap(x, y);
ans += Ask(dfn[tp[x]], dfn[x]);
x = fa[tp[x]]; ans += s[x];
}
if (dfn[x] > dfn[y]) swap(x, y);
if (x == n + 1 || (x == tmp && fa[x] == n + 1)) { puts("?"); continue; }
ans += Ask(dfn[x], dfn[y]);
if (x == tp[x]) ans += s[fa[x]];
if (x == tmp) {
x = fa[tmp];
ans += Ask(dfn[x], dfn[x]);
if (x == tp[x]) ans += s[fa[x]];
}
printf("%lld\n", ans);
}
}
return 0;
}
B 蓝超巨星 (Unaccepted)
题目大意 :
Code
Show Code
C 秘密行动
题目大意 : 每个位置的每个可选的质数有选和不算的代价,还有一些限制,两个位置选择某个质数的状态不同则还有个代价,问最小代价积
-
除了我大概都能看出来是网络流吧。
-
取对数可以做到把乘转换成加,就成了求最小代价和
-
s向每个位置的每个质数连选的代价,质数向t连不选的代价,限制的话就两个质数连双向边,流量为差异代价,然后跑最小割就行
-
如果写Dinic是return的是lim-sum,那开始传进去的lim不能太大
Code
Show Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define double long double
using namespace std;
const int N = 505;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
return x * f;
}
struct Edge {
int n, t; double f;
}e[N*2];
int h[N], edc = 1, tmp[N];
void Add(int x, int y, double d) {
e[++edc] = (Edge) {h[x], y, d}; h[x] = edc;
e[++edc] = (Edge) {h[y], x, 0}; h[y] = edc;
}
double f[N], ans;
int n, m, id[N][N], s, t, idc, dep[N], q[N];
bool Bfs() {
memset(dep + 1, 0, t * 4);
memcpy(h + 1, tmp + 1, t * 4);
int l = 1, r = 1; q[1] = s; dep[s] = 1;
while (l <= r) {
int x = q[l++];
for (int i = h[x], y; i; i = e[i].n) {
if (!e[i].f || dep[y=e[i].t]) continue;
dep[y] = dep[x] + 1; q[++r] = y;
if (y == t) return 1;
}
}
return 0;
}
double Dinic(int x, double lim) {
if (x == t) return lim;
double sum = 0;
for (int i = h[x]; i && lim; i = e[i].n) {
int y = e[i].t; h[x] = i;
if (!e[i].f || dep[y] != dep[x] + 1) continue;
double f = Dinic(y, min(lim, e[i].f));
lim -= f; sum += f;
e[i].f -= f; e[i^1].f += f;
}
if (!sum) dep[x] = 0;
return sum;
}
int main() {
freopen("secret.in", "r", stdin);
freopen("secret.out", "w", stdout);
n = read(); m = read();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= 10; ++j)
id[i][j] = ++idc;
s = ++idc, t = s + 1;
for (int i = 1, x; i <= 10; ++i)
read(), scanf("%Lf", &f[i]);
for (int i = 1; i <= n; ++i) {
double x;
for (int j = 1; j <= 10; ++j)
scanf("%Lf", &x), Add(s, id[i][j], log2(x));
for (int j = 1; j <= 10; ++j)
scanf("%Lf", &x), Add(id[i][j], t, log2(x));
}
while (m--) {
int x = read(), y = read(), z = read();
Add(id[x][z], id[y][z], log2(f[z]));
Add(id[y][z], id[x][z], log2(f[z]));
}
memcpy(tmp + 1, h + 1, t * 4);
while (Bfs()) ans += Dinic(s, 1e18);
printf("%.10Lf\n", pow(2, ans));
return 0;
}