A层省选1
A. 点点的圈圈
瓶颈在建图,用类似扫描线的方法求解
根据\((x_i - x)^2 + (y_i - y) ^ 2 = r ^2\)在已知\(x, r\)时可以\(O(1)\)求出\(y\)
我们将圆在\(x - r\)加入, \(x + r\)删除, 并且拆成上下两个半圆
用平衡树维护扫描线,按照\(y\)为第一关键字, 上下半圆为第二关键字维护,可以发现由于圆与圆只有包含与不交的关系,那么两个圆在平衡树中的相对位置是不会改变的,所以只用在插入的过程中考虑位置,之后需要使用时直接计算,不用移动
当插入一个圆时,在平衡树找出它的下半圆的前驱,由于只有包含与不相交,那么如果前驱是个下半圆,那么当前圆的父亲即为前驱,否则前驱是该圆的兄弟
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
const int maxn = 100005;
struct circle{int x, y, r, w;}a[maxn];
struct opt{
int op, id, pos;
opt(){}
opt(int op_, int id_, int pos_){op = op_, id = id_, pos = pos_;}
friend bool operator < (const opt &x,const opt &y){
return x.pos < y.pos;
}
}o[maxn << 1 | 1];
int n, X, fa[maxn], val[maxn], rd[maxn];
queue<int>q;
struct node{
int type, id;
node(){}
node(int tp, int i){type = tp, id = i;}
double pos() const{
return a[id].y + type * sqrt(1ll * a[id].r * a[id].r - 1ll * (a[id].x - X) * (a[id].x - X));
}
friend bool operator <(const node &x,const node &y){
double aa = x.pos(), bb = y.pos();
return aa != bb ? aa < bb : x.type < y.type;
}
};
set<node>s;
int main(){
n = read();
for(int i = 1; i <= n; ++i){
a[i].x = read(), a[i].y = read(), a[i].r = read(), a[i].w = read();
o[i + i - 1] = opt(1, i, a[i].x - a[i].r), o[i + i] = opt(0, i, a[i].x + a[i].r);
}
sort(o + 1, o + n + n + 1);
for(int i = 1; i <= n + n; ++i){
X = o[i].pos;
if(o[i].op == 1){
int id = o[i].id; auto it = s.lower_bound(node(1,id));
if(it != s.end())fa[id] = it->type == 1 ? it->id : fa[it->id];
s.insert(node(1, o[i].id)), s.insert(node(-1, o[i].id));
}else{ s.erase(node(1,o[i].id)), s.erase(node(-1,o[i].id));}
}
for(int i = 1; i <= n; ++i)if(fa[i])++rd[fa[i]];
for(int i = 1; i <= n; ++i)if(!rd[i])q.push(i);
while(!q.empty()){
int x = q.front(); q.pop();
val[x] = max(val[x], a[x].w);
if(fa[x]){ --rd[fa[x]]; if(rd[fa[x]] == 0)q.push(fa[x]);}
val[fa[x]] += val[x];
}
printf("%d\n",val[0]);
return 0;
}
B. 点点的计算
简单证明一下,考虑当前位置前一个为\(b\), 前面的上面为\(a\),那么当前数为\(ab/(b - a)\)
那么实际上就是求\(ab^2/(b - a)/gcd(b, ab/(b - a))\)
\(=ab^2/gcd(b^2 - ab, ab)\)
\(=ab/gcd(b - a, a)\)
\(=lcm(a, b)\)
使用主席树维护答案,第\(i\)个版本维护第\(i\)行的答案,其实可以看做一个\(1 - i\)的前缀的后缀的答案
前\(i - 1\)个信息可以继承上个版本,新位置需要插入\(i\)保持答案的正确性,那么我们需要找出前若干个因子,消去他们的影响
假设\(i = p^a\)其中\(p\)为一个质数,那么前\(a\)个\(p\)因子的影响需要消除,具体做法是在对应位置乘上\(inv_p\),找位置的方法就是\(i - p ^ j (j \in [1, min(p, b)])\)其中\(b\)为之前出现过的\(p\)的最高次幂
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
const int maxn = 200005;
const int mod = 1e9 + 7;
int c[maxn], d[maxn], prime[maxn], cnt, inv[maxn], yz[maxn], s[maxn];
bool flag[maxn];
int root[maxn];
struct tree{
struct node{
int l, r, val;
node(){val = 1;}
}t[maxn << 6 | 1];
void modify(int &x, int l, int r, int pos, int val){
t[++cnt] = t[x]; x = cnt;
t[x].val = 1ll * t[x].val * val % mod;
if(l == r)return;
int mid = (l + r) >> 1;
if(pos <= mid)modify(t[x].l, l, mid, pos, val);
else modify(t[x].r, mid + 1, r, pos ,val);
}
int query(int x, int l, int r, int L, int R){
if(L <= l && r <= R)return t[x].val;
int mid = (l + r) >> 1, ans = 1;
if(L <= mid)ans = ans * query(t[x].l, l, mid, L, R);
if(R > mid)ans = 1ll * ans * query(t[x].r, mid + 1, r, L, R) % mod;
return ans;
}
}t;
int main(){
int Q = read(), n = read(), k = read();
int a = read(), b = read(), m = read();
for(int i = 1; i < Q; ++i)c[i] = read();
for(int i = 1; i < Q; ++i)d[i] = read();
inv[1] = 1;
for(int i = 2; i <= m; ++i)inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
for(int i = 2; i <= m; ++i){
if(!flag[i])prime[++cnt] = i, yz[i] = i;
for(int j = 1; j <= cnt && i * prime[j] <= m; ++j){
flag[i * prime[j]] = 1;
yz[i * prime[j]] = prime[j];
if(i % prime[j] == 0)break;
}
}
for(int i = 2; i <= m; ++i){
int now = i;
t.modify(root[i] = root[i - 1], 1, m, i, i);
while(yz[now]){
int mp = yz[now], num = 0, sum = mp;
while(now % mp == 0) now /= mp, ++num;
if(num > s[mp])swap(num, s[mp]);
while(num){
t.modify(root[i], 1, m, i - sum, inv[mp]);
sum = sum * mp;
--num;
}
}
}
int ans = 0;
for(int i = 1; i <= Q; ++i){
ans = t.query(root[n], 1, m, n - k + 1, n);
printf("%d\n",ans);
n = (1ll * a * ans + c[i]) % m + 1;
k = (1ll * b * ans + d[i]) % n + 1;
}
return 0;
}
C. 点点的最大流
学长都用的\(lct\),可是我这个蒟蒻还没学,题解做法有亿点恶心,先跑了
code暴力56pts
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
const int maxn = 200005;
const int inf = 2147483647;
int head[maxn],tot;
struct edge{
int to, net, val;
}e[maxn << 2 | 1];
void add(int u, int v ,int w){
e[++tot].net = head[u];
head[u] = tot;
e[tot].to = v;
e[tot].val = w;
}
int n, m;
int fa[maxn], son[maxn], size[maxn], dep[maxn], id[maxn], tim, nid[maxn], va[maxn], top[maxn];
struct tree{
int t[maxn << 4 | 1];
void push_up(int x){t[x] = min(t[x << 1], t[x << 1 | 1]);}
void built(int x, int l, int r){
if(l == r){
t[x] = va[nid[l]];
return;
}
int mid = (l + r) >> 1;
built(x << 1, l, mid);
built(x << 1 | 1, mid + 1 , r);
push_up(x);
}
void modify(int x, int l, int r, int pos, int val){
if(l == r){
t[x] = val;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid)modify(x << 1, l, mid, pos ,val);
else modify(x << 1 | 1, mid + 1 , r , pos , val);
push_up(x);
}
int query(int x, int l, int r, int L, int R){
if(L <= l && r <= R)return t[x];
int mid = (l + r) >> 1, ans = inf;
if(L <= mid)ans = min(ans, query(x << 1, l, mid, L, R));
if(R > mid)ans = min(ans, query(x << 1 | 1, mid + 1, r ,L, R));
return ans;
}
}t;
void dfs1(int x){
size[x] = 1;
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == fa[x])continue;
fa[v] = x; dep[v] = dep[x] + 1;
dfs1(v);
size[x] += size[v];
if(size[v] > size[son[x]])son[x] = v;
}
}
void dfs2(int x, int tp){
id[x] = ++tim; nid[tim] = x;
top[x] = tp;
if(son[x])dfs2(son[x], tp);
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(v == fa[x])continue;
va[v] = e[i].val;
if(v == son[x])continue;
dfs2(v, v);
}
}
int get(int u, int v){
int ans = inf;
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]])swap(u ,v);
ans = min(ans, t.query(1, 1, n, id[top[u]], id[u]));
u = fa[top[u]];
}
if(u == v)return ans;
if(dep[u] < dep[v])swap(u, v);
ans = min(ans, t.query(1, 1, n, id[v] + 1, id[u]));
return ans;
}
void modify(int x, int f){
int u = e[x << 1].to;
int v = e[(x << 1) - 1].to;
if(dep[u] < dep[v])u = v;
t.modify(1, 1, n, id[u], f);
}
void work_1(){
for(int i = 1; i <= m; ++i){
int u = read(), v = read(), w = read();
add(u, v, w); add(v, u, w);
}
dep[1] = fa[1] = 1;
dfs1(1);
dfs2(1, 1);
t.built(1, 1, n);
int Q = read();
for(int i = 1; i <= Q; ++i){
int op = read(), s = read(), t = read();
if(op)modify(s, t);
else printf("%d\n",get(s, t));
}
}
struct wll{
void pre(){
for(int i = 2; i <= tot; i += 2){
e[i].val = e[i + 1].val = (e[i].val + e[i + 1].val) / 2;
}
}
void upd(int x, int f){
e[x << 1].val = f;
e[x << 1 | 1].val = f;
}
int now[maxn];
bool bfs(int s, int t){
for(int i = 1; i <= n; ++i)dep[i] = 0;
dep[s] = 1; now[s] = head[s];
queue<int>q;q.push(s);
while(!q.empty()){
int x = q.front(); q.pop();
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(e[i].val > 0 && !dep[v]){
dep[v] = dep[x] + 1;
now[v] = head[v];
if(v == t)return true;
q.push(v);
}
}
}
return false;
}
int dfs(int x, int from, int t){
if(from <= 0 || x == t)return from;
int res = from, i;
for(i = now[x]; i; i = e[i].net){
int v = e[i].to;
if(dep[v] == dep[x] + 1 && e[i].val > 0){
int k = dfs(v, min(res, e[i].val), t);
if(k <= 0)dep[v] = 0;
res -= k;
e[i].val -= k;
e[i ^ 1].val += k;
if(res <= 0)break;
}
}
now[x] = i;
return from - res;
}
int dinic(int s, int t){
pre();
int ans = 0;
while(bfs(s, t))ans += dfs(s, inf, t);
return ans;
}
}w;
void work(){
tot = 1;
for(int i = 1; i <= m; ++i){
int u = read(), v = read(), w = read();
add(u, v, w); add(v, u, w);
}
int Q = read();
for(int i = 1; i <= Q; ++i){
int op = read(), s = read(), t = read();
if(op)w.upd(s ,t);
else printf("%d\n",w.dinic(s, t));
}
}
int main(){
n = read(); m = read();
if(m == n - 1) work_1();
else work();
return 0;
}
网络流没打挂\(QAQ\)