[Competition] [Provincial Team Ten-consecutive Test Promotion Competition 2017]
Pre()
This is the first game played by BZOJ and the first game question written in the blog...
T1
Main idea of the title:
Given a rooted tree with N<=100,000 nodes, let sum[i] be the weight of a subtree with I as its root. Command 1U V changes the weight of node u to v, and command 2lr asks ri=lsum[i].
Train of thought:
The idea at first was to divide the tree up and find that it was not possible to do it. Then consider dividing the sum sequence into N_blocks. Preprocessing f[i][j] is the number of blocks I in the ancestor of node j. This should be well preprocessed. Obviously, in dfs, the following formula is handled (where u is the father of v):
In this way, a s[i] i s preprocessed to represent the sum weight of block I. If the weight of node numbered u i s changed from x to y, then each block i s processed as follows:
This formula obviously holds (the weight change of a node contributes to y_x for both it and its father, and the number of fathers in each block has been pre-processed before).
The query of block and block as a whole has been pre-processed, so what if there are some points besides blocks on both sides of the block when querying?
Let's first deal with the dfs order to sort a tree into a sequence. A point and its subtree must be a continuous segment in the sequence. When we modify a single point, we also modify the position of the point vdfs order on the tree array. Then, when we do statistics, we violence the scattered points to count its subtree sum (tree array query sequence and sum).
When modifying, each block should be modified once. Complexity O(N__), query block has O(N) at most, scattered point has O(N_) at most. O(N_) is used at every point in the pretreatment.
So the total complexity is O((N+M)N)
Pit:
Both operations of the tree array are wrong... Contributed a page of RE.
And if all the LR s asked are in the same block, just do it violently once.
To open unsigned long distance
Code:
#include <bits/stdc++.h>
const int Maxn = 100110;
typedef unsigned long long ll;
using namespace std;
inline char get(void) {
static char buf[1000000], *p1 = buf, *p2 = buf;
if (p1 == p2) {
p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
if (p1 == p2) return EOF;
}
return *p1++;
}
inline void read(int &x) {
x = 0; static char c;
for (; !(c >= '0' && c <= '9'); c = get());
for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get());
}
inline void read(ll &x) {
x = 0; static char c;
for (; !(c >= '0' && c <= '9'); c = get());
for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get());
}
inline void write(ll x) {
if (!x) return (void)puts("0");
if (x < 0) putchar('-'), x = -x;
static short s[60], t;
while (x) s[++t] = x % 10, x /= 10;
while (t) putchar('0' + s[t--]);
putchar('\n');
}
int n, m;
ll t[Maxn];
inline void insert(int x, long long v) {
for (; x < Maxn; x += (x & -x)) t[x] += v;
}
inline ll query(int x) {
ll ret = 0;
for (; x > 0; x -= (x & -x)) ret += t[x];
return ret;
}
int head[Maxn], sub;
struct Edge {
int to, nxt;
Edge(void) {}
Edge(const int &to, const int &nxt) : to(to), nxt(nxt) {}
} edge[Maxn << 1];
inline void add(const int &a, const int &b) {
edge[++sub] = Edge(b, head[a]), head[a] = sub;
}
ll sum[320], a[Maxn];
int bb[320][Maxn], st[Maxn], ed[Maxn];
int block, belong[Maxn], root, dfn[Maxn], en[Maxn], ff;
inline void dfs(int u, int fa) {
dfn[u] = ++ff;
bb[belong[u]][u]++;
for (int i = head[u], v; i; i = edge[i].nxt) {
v = edge[i].to;
if (fa == v) continue;
for (int k = 1; k <= block; k++)
bb[k][v] = bb[k][u];
dfs(v, u);
}
en[u] = ff;
}
int main(void) {
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
read(n), read(m);
for (int i = 1; i <= n; i++) read(a[i]);
for (int i = 1; i <= n; i++) {
int a, b;
read(a), read(b);
if (!a || !b) {
root = a ^ b;
continue;
}
add(a, b), add(b, a);
}
block = sqrt(n) + 1;
for (int i = 1; i <= n; i++) {
belong[i] = (i - 1) / block + 1;
ed[belong[i]] = i;
if (!st[belong[i]]) st[belong[i]] = i;
}
dfs(root, 0);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= block; j++) {
sum[j] += bb[j][i] * a[i];
}
insert(dfn[i], a[i]);
}
int x, wa, al, bl;
ll y, ret;
//cout << "ok" << endl;
while (m--) {
read(wa), read(x), read(y);
if (wa == 2) {
ret = 0;
al = belong[x]; bl = belong[y];
if (al == bl) {
for (int i = x; i <= y; i++) ret += query(en[i]) - query(dfn[i] - 1);
write(ret);
continue;
}
for (int i = al + 1; i < bl; i++)
ret += sum[i];
for (int i = x; i <= ed[al]; i++) {
ret += query(en[i]) - query(dfn[i] - 1);
}
for (int i = st[bl]; i <= y; i++) {
ret += query(en[i]) - query(dfn[i] - 1);
}
write(ret);
} else {
for (int i = 1; i <= block; i++)
sum[i] = sum[i] + (long long) bb[i][x] * (y - a[x]);
insert(dfn[x], y - a[x]);
a[x] = y;
}
}
return 0;
}
T2
Main idea of the title:
Given that one side point is n and the other side point is m, the number of spanning trees of a labeled complete bipartite graph Kn,m with a total of NMS edges is calculated.
The answer is%p.
Train of thought:
Good God, ah no, one of the great gods in the computer room found that is the conclusion.
The answer is: (nm_1_mn_1)%p
So the fast power set multiplies the water quickly...
Complexity seems to be O(log2N)
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL fast_multi(LL m, LL n, LL mod)
{
LL ans = 0;
while (n)
{
if (n & 1)
ans += m;
m = (m + m) % mod;
m %= mod;
ans %= mod;
n >>= 1;
}
return ans;
}
LL fast_pow(LL a, LL n, LL mod)
{
LL ans = 1;
while (n)
{
if (n & 1)
ans = fast_multi(ans, a, mod);
a = fast_multi(a, a, mod);
ans %= mod;
a %= mod;
n >>= 1;
}
return ans;
}
LL a, b, c;
int main(void) {
cin >> a >> b >> c;
cout << fast_multi(fast_pow(a, b - 1, c), fast_pow(b, a - 1, c), c) << endl;
return 0;
}
T3
Main idea of the title:
Given two mobile modes (u,v)> (u + Ax, V + Ay), (u,v)> (u + Bx, V + By), find out how many methods to move from (0, 0) to (Ex,Ey).
Want% 1000000007
Train of thought:
Consider moving from (0,0) to (ex,ey) as a group of equations about (M,N) (M represents the number of methods used in the first and N represents the number of methods used in the second):
Move from (0,0) to (ex,ey) if and only if the solution of N and M is a positive integer.
And for the determined (ex,ey), the corresponding (M,N) must be unique (the properties of the binary system of first order equations).
In this way, we can rebuild the graph into a grid with coordinates (M,N).
The number of schemes to move from (0,0) to (ex,ey) is CMN+M.
Considering DP+inclusion and exclusion, all points on the grid graph are ranked in ascending order with N as the first key and M as the second key. After filtering out the points whose M or N are larger than the final point, f[i] is defined as the number of legitimate schemes to reach the point I (after sorting).
The equation of state transition is:
The factorial and inverse elements should be pre-processed when dealing with permutation numbers. Of course, the inverse element, like me, can also be fast powered.
Code:
#include <bits/stdc++.h>
const int Maxn = 510;
const int Mod = 1000000007;
typedef long long ll;
using namespace std;
inline char get(void) {
static char buf[1000000], *p1 = buf, *p2 = buf;
if (p1 == p2) {
p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
if (p1 == p2) return EOF;
}
return *p1++;
}
inline void read(ll &x) {
x = 0; static char c; bool f = 0;
for (; !(c >= '0' && c <= '9'); c = get()) if (c == '-') f = 1;
for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get()); if (f) x = -x;
}
ll aX, aY, bX, bY, tot;
ll power(ll a, ll b) {
ll ret = 1;
while (b) {
if (b & 1) (ret *= a) %= Mod;
(a *= a) %= Mod;
b >>= 1;
}
return ret;
}
ll ff[1000001];
ll fab(ll n) {
return ff[n];
}
ll C(ll n, ll m) {
ll a = fab(n + m), b = fab(m), c = fab(n);
return a * power(b, Mod - 2) % Mod * power(c, Mod - 2) % Mod;
}
ll CC(ll n, ll m) {
if (n < 0 || m < 0) return 0;
else return C(n, m);
}
ll N, M, NN, MM;
inline void Clac(ll Ex, ll Ey) {
ll t1 = (bY * aX - bX * aY), t2 = (Ey * aX - Ex * aY);
if (t2 % t1 != 0) {
N = -1;
return;
}
N = t2 / t1;
t1 = (bX * aY - bY * aX), t2 = (Ey * bX - Ex * bY);
if (t2 % t1 != 0) {
M = -1;
return ;
}
M = t2 / t1;
if (M < 0 || N < 0) return;
}
ll n, f[Maxn];
struct Pos {
ll x, y;
friend bool operator < (const Pos &a, const Pos &b) {
if (a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
} pos[Maxn];
int main(void) {
ll init = 1;
ff[0] = 1;
for (int i = 1; i <= 1000000; i++) {
init = (init * i) % Mod;
ff[i] = init;
}
ll Ex, Ey, tot = 0;
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
read(Ex), read(Ey), read(n);
read(aX), read(aY), read(bX), read(bY);
Clac(Ex, Ey); MM = M, NN = N;
ll x, y;
for (ll i = 1; i <= n; i++) {
read(x), read(y);
Clac(x, y);
if (N < 0 || M < 0 || N > NN || M > MM) continue;
tot++;
pos[tot].x = N, pos[tot].y = M;
}
tot++;
pos[tot].x = NN, pos[tot].y = MM;
sort(pos + 1, pos + 1 + tot);
for (ll i = 1; i <= tot; i++) {
f[i] = CC(pos[i].x, pos[i].y);
for (ll j = 1; j < i; j++)
if (pos[j].y <= pos[i].y)
f[i] = (f[i] + Mod - (CC(pos[i].x - pos[j].x, pos[i].y - pos[j].y) * f[j]) % Mod) % Mod;
}
for (ll i = tot; i; i--) {
if (f[i]) {
cout << f[i] << endl;
return 0;
}
}
cout << 0 << endl;
return 0;
}
Scatter flowers ~