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. 点点的计算

image

简单证明一下,考虑当前位置前一个为\(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\)

posted @ 2022-08-09 21:39  Chen_jr  阅读(25)  评论(0编辑  收藏  举报