首页 > 其他分享 >省选模拟系列

省选模拟系列

时间:2023-01-30 17:25:48浏览次数:46  
标签:dep 系列 省选 long int maxn return include 模拟

省选模拟之辞旧迎新1

A. 神必的集合

不太理解

code
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cassert>
#include<cstring>
#include<complex>
#include<iostream>
#include<algorithm>
#include<unordered_map>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
#define int long long
int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}
const int maxn = 405;
const int mod = 998244353;

void add(int &x, int y){x += y; if(x >= mod)x -= mod;}
int n, m, rk[maxn], a[maxn], f[65], dp[65][65], p2[65];
void ins(int x){
	for(int i = n - 1; i >= 0; --i)if((x >> i) & 1){
		if(!f[i])f[i] = x, i = 0;
		else x ^= f[i];
	}
}
int solve(){
	for(int i = 0; i <= n; ++i)p2[i] = (1ll << n) - 1;
	for(int i = 1; i <= m; ++i)ins(a[i]);
	int mx = 0;
	for(int j = 1; j <= m; ++j){
		int nowa = a[j], d = rk[j];
		for(int i = 0; i < n; ++i){
			if((d >> i) & 1)p2[i + 1] &= nowa, mx = max(mx, i + 1);
			else p2[i + 1] &= (p2[0] ^ nowa);
		}
	}
	if(!f[0])dp[0][0] = 1; if(p2[1] & 1)dp[0][1] = 1;
	for(int i = 1; i < n; ++i){
		if(f[i]){
			for(int j = 1; j <= i + 1; ++j)if((p2[j] >> i) & 1)
				add(dp[i][j], dp[i - 1][j - 1]);
		}else{
			for(int j = 1; j <= i + 1; ++j)if((p2[j] >> i) & 1)
				add(dp[i][j], (1ll << (i + 1 - j)) % mod * dp[i - 1][j - 1] % mod);
			for(int j = 0; j <= i; j++)add(dp[i][j], dp[i - 1][j]);
		}
	}
	int ans = 0;
	for(int i = mx; i <= n; ++i)
		add(ans, dp[n - 1][i]);
	return ans;
}
signed main(){
	freopen("set.in","r",stdin);
	freopen("set.out","w",stdout);
	n = read(), m = read();
	for(int i = 1; i <= m; ++i)rk[i] = read() - 1, a[i] = read();
	printf("%d\n", solve());
	return 0;
}

B. 法阵

原题见

https://www.cnblogs.com/Chencgy/p/16760114.html

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

inline int read(){
	int x = 0; char c = getchar();
	while(c < '0' || c > '9')c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
	return x;
}

const int maxn = 500005;
int a[maxn], n;

struct query{
	int l, r, id;
	friend bool operator < (const query &x, const query &y){
		return x.l > y.l;
	}
}q[maxn];
struct seg{
	struct node{
		ll tag, val, mx;
	}t[maxn << 2 | 1];
	void push_up(int x){
		t[x].mx = max(t[x << 1].mx, t[x << 1 | 1].mx);
		t[x].val = max(t[x << 1].val , t[x << 1 | 1].val);
	}
	void built(int x, int l, int r){
		if(l == r){
			t[x].mx = a[l];
			return;
		}
		int mid = (l + r) >> 1;
		built(x << 1, l, mid);
		built(x << 1 | 1, mid + 1, r);
		push_up(x);
	}
	void upd(int x, ll val){
		t[x].tag = max(t[x].tag, val);
		t[x].val = max(t[x].val, t[x].mx + val);
	}
	void push_down(int x){
		upd(x << 1, t[x].tag);
		upd(x << 1 | 1, t[x].tag);
		t[x].tag = 0;
	}
	void modify(int x, int l, int r, int L, int R, ll val){
		if(L > R)return;
		if(L <= l && r <= R){
			upd(x, val);
			return;
		}
		if(t[x].tag)push_down(x);
		int mid = (l + r) >> 1;
		if(L <= mid)modify(x << 1, l, mid, L, R, val);
		if(R > mid)modify(x << 1 | 1, mid + 1, r, L ,R, val);
		push_up(x);
	}
	ll query(int x, int l, int r, int L, int R){
		if(L <= l && r <= R)return t[x].val;
		if(t[x].tag)push_down(x);
		int mid = (l + r) >> 1;
		ll ans = 0;
		if(L <= mid)ans = max(ans, query(x << 1, l, mid, L, R));
		if(R > mid)ans = max(ans, query(x << 1 | 1, mid + 1, r, L, R));
		return ans;
	}
}t;
int sta[maxn], top;
ll ans[maxn];
void pop(int x){
	t.modify(1, 1, n, sta[top] + sta[top] - x, n, a[sta[top]] + a[x]);
	--top;
}
void push(int x){
	if(top)t.modify(1, 1, n, sta[top] + sta[top] - x, n, a[sta[top]] + a[x]);
	sta[++top] = x;
}
int main(){
	freopen("fz.in","r",stdin);
	freopen("fz.out","w",stdout);
	n = read();
	for(int i = 1; i <= n; ++i)a[i] = read();
	t.built(1, 1, n);
	int Q = read();
	for(int i = 1; i <= Q; ++i){
		q[i].l = read(); q[i].r = read(); q[i].id = i;
	}
	sort(q + 1, q + Q + 1);
	int pq = 1;
	for(int i = n; i >= 1; --i){
		while(top && a[sta[top]] <= a[i])pop(i);
		push(i);
		while(pq <= Q && q[pq].l >= i){
			ans[q[pq].id] = t.query(1, 1, n, q[pq].l, q[pq].r);
			++pq;
		}
	}
	for(int i = 1; i <= Q; ++i)printf("%lld\n",ans[i]);
	return 0;
}

C. 旅行

暴力连边优化,在点分治时候连边,对每个深度开一个虚点

详细看学长的博客吧

https://www.cnblogs.com/MaxQAQ/p/16010035.html

题解做法是建立点分树,不过跟这个本质类似

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> pli;
int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}
const int maxn = 2e5 + 55;
const ll inf = 0x3f3f3f3f3f3f3f3f;
int n, m, cnt, rem[maxn];
struct DSU{
	int f[maxn];
	void init(){for(int i = 1; i <= n; ++i)f[i] = i;}
	int fa(int x){return f[x] == x ? x : f[x] = fa(f[x]);}
	bool merge(int x, int y){x = fa(x); y = fa(y); if(x == y)return false; f[y] = x; return true;}	
}s;

int d[maxn], c[maxn];
struct EDGE{int x, y;}E[maxn];
vector<int>g[maxn];
bool del[maxn], vis[maxn * 150], in[maxn];
int dis[maxn * 150];

ll ans[maxn * 150];
priority_queue<pli, vector<pli>, greater<pli>>q;
struct edge{int to, net, val;}e[maxn * 150];
int head[maxn * 40], tot;
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 S, mx[maxn], si[maxn], root, mxd, dep[maxn];
void getroot(int x, int fa){
	si[x] = 1; mx[x] = 0;
	for(int v : g[x])if(!del[v] && v != fa){
		getroot(v, x);
		si[x] += si[v];
		mx[x] = max(mx[x], si[v]);
	}
	mx[x] = max(mx[x], S - si[x]);
	if(mx[x] < mx[root])root = x;
}
void dfs1(int x, int fa){
	mxd = max(mxd, dep[x]);
	for(int v : g[x])if(!del[v] && v != fa){
		dep[v] = dep[x] + 1;
		dfs1(v, x);
	}
}
void dfs2(int x, int fa){
	add(rem[dep[x]], x, 0);
	if(d[x] >= dep[x])add(x, rem[min(mxd, d[x] - dep[x])], c[x]);
	for(auto v : g[x])if(!del[v] && v != fa)dfs2(v, x);
}
void calc(int x){
	mxd = 0;
	dep[x] = 0; dfs1(x, 0);
	for(int i = 0; i <= mxd; ++i)rem[i] = ++cnt;
	for(int i = 1; i <= mxd; ++i)add(rem[i], rem[i - 1], 0);
	dfs2(x, 0);
}
void solve(int x){
	del[x] = 1; calc(x);
	for(int v : g[x])if(!del[v]){
		S = si[v]; root = 0;
		getroot(v, x); solve(root);
	}
}
void bfs(int S){
	queue<int>q;
	for(int i = 1; i <= n; ++i)dis[i] = 0x3f3f3f3f; dis[S] = 0; q.push(S);
	while(!q.empty()){
		int x = q.front(); q.pop();
		for(int v : g[x])if(dis[v] > dis[x] + 1){
			dis[v] = dis[x] + 1;
			q.push(v);
		}
	}
}
int main(){
	freopen("travel.in","r",stdin);
	freopen("travel.out","w",stdout);
	n = read(), m = read(); s.init();
	for(int i = 1; i <= m; ++i)E[i].x = read(), E[i].y = read();
	for(int i = 1; i <= n; ++i)d[i] = read(), c[i] = read();
	for(int i = 1; i <= m; ++i)if(s.merge(E[i].x, E[i].y)){
		in[i] = true; g[E[i].x].push_back(E[i].y); g[E[i].y].push_back(E[i].x);
	}
	cnt = S = n; mx[0] = n + n; getroot(1, 0); solve(root);
	for(int i = 1; i <= m; ++i)if(!in[i]){
		g[E[i].x].push_back(E[i].y); 
		g[E[i].y].push_back(E[i].x);
	}
	for(int i = 1; i <= m; ++i)if(!in[i]){
		bfs(E[i].x); int mxd = 0;
		for(int j = 1; j <= n; ++j)mxd = max(mxd, dis[j]);
		for(int j = 0; j <= mxd; ++j)rem[j] = ++cnt;
		for(int j = 1; j <= n; ++j)add(rem[dis[j]], j, 0);
		for(int j = 1; j <= mxd; ++j)add(rem[j], rem[j - 1], 0);
		for(int j = 1; j <= n; ++j)if(d[j] >= dis[j])add(j, rem[min(d[j] - dis[j], mxd)], c[j]);
	}

	for(int i = 1; i <= cnt; ++i)ans[i] = inf; q.push(pli(0, 1)); ans[1] = 0;
	while(!q.empty()){
		int x = q.top().second; q.pop(); 
		if(vis[x])continue;
		vis[x] = true;
		for(int i = head[x]; i; i = e[i].net){
			int v = e[i].to;
			if(ans[v] > ans[x] + e[i].val){
				ans[v] = ans[x] + e[i].val;
				q.push(pli{ans[v], v});
			}
		}
	}
	for(int i = 2; i <= n; ++i)printf("%lld\n",ans[i]);
	return 0;
}

省选模拟之辞旧迎新2

A. 小 F 与游戏

阿巴阿巴

code
#include<bits/stdc++.h>

using namespace std;
int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}
const int maxn = 1e6 + 55, mx = 1e6;
int n, k, mod, fac[maxn], ifac[maxn];
int qpow(int x, int y){
	int ans = 1;
	for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
	return ans;
}
inline int c(int n,int m){return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;}
signed main(){
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	n = read(); k = read(); mod = read();
	fac[0] = ifac[0] = 1; for(int i = 1; i <= mx; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
	ifac[mx] = qpow(fac[mx], mod - 2);
	for(int i = mx - 1; i >= 1; --i)ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
	if(k == 1){
		printf("%d\n", qpow(2,n - 2));
		return 0;
	}
	if(n==k){
		printf("%d\n",(c(n + n - 2, n - 1) - c(n + n - 2, n - 2) + mod) % mod);
		return 0;
	}
	printf("%d\n",1ll * qpow(2, n - k - 1) * ( c(n + k - 2, k - 1) - c(n + k - 2, k - 2) + mod) % mod);
	return 0;
}

B. 小 Z 与函数

不考虑 \(vs\), 剩下的就是顺序对

现在考虑如何得到 \(vs\)

考虑执行完 \(i - 1\) 轮之后

第 \(i\) 个位置上是 \([1, i]\) 的最小值,而此次循环首次产生贡献的位置是后面第一个比最小值大的数

把贡献放到那个位置即可

但是可能会有重复选择同一个位置的情况,那么记录对于每个最小值上次选择的位置在哪里,作为查询的左界即可

code
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cassert>
#include<cstring>
#include<complex>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define int long long
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}

const int maxn = 600005;
int n, b[maxn];
struct BIT{
	int t[maxn];
	int lowbit(int x){return x & -x;}
	void add(int x){
		while(x <= n){
			++t[x];
			x += lowbit(x);
		}
	}
	int query(int x){
		int ans = 0;
		while(x){
			ans += t[x];
			x -= lowbit(x);
		}
		return ans;
	}
	void clear(){
		for(int i = 1; i <= n; ++i)t[i] = 0;
	}
}t;
struct seg{
	int t[maxn << 2 | 1];
	void build(int x, int l, int r){
		if(l == r){
			t[x] = b[l];
			return;
		}
		int mid = (l + r) >> 1;
		build(x << 1, l, mid);
		build(x << 1 | 1, mid + 1, r);
		t[x] = max(t[x << 1], t[x << 1 | 1]);
	}
	int query(int x, int l, int r, int L, int R, int val){
		if(t[x] <= val)return n + 1;
		if(l == r)return l;
		int mid = (l + r) >> 1;
		if(L <= l && r <= R){
			if(t[x << 1] > val)return query(x << 1, l, mid, L, R, val);
			return query(x << 1 | 1, mid + 1, r, L, R, val);
		}
		int res = n + 1;
		if(L <= mid && t[x << 1] > val)res = query(x << 1, l, mid, L, R, val);
		if(res == n + 1 && R > mid && t[x << 1 | 1] > val)res = query(x << 1 | 1, mid + 1, r, L, R, val);
		return res;
	}
}T;
int las[maxn], cnt[maxn];

void solve(){
	n = read(); 
	for(int i = 1; i <= n; ++i)b[i] = read();
	ll ans = 0; int mi = 0x3f3f3f3f;
	T.build(1, 1, n);
	for(int i = 1; i <= n; ++i){
		ans += t.query(b[i] - 1); 
		ans += cnt[i];
		mi = min(mi, b[i]);
		int pos = max(i, las[mi]) + 1; 
		if(pos <= n){pos = T.query(1, 1, n, pos, n, mi); ++cnt[pos];}
		las[mi] = pos;
		if(t.query(b[i]) == t.query(b[i] - 1))t.add(b[i]);
		printf("%lld ",ans); 
	}
	printf("\n");
	for(int i = 1; i <= n + 5; ++i)las[i] = cnt[i] = 0;
	t.clear();
}

signed main(){
	freopen("function.in","r",stdin);
	freopen("function.out","w",stdout);
	int t = read();
	for(int i = 1; i <= t; ++i)solve();
	return 0;
}

C. 小 W 与骑士

如果平行,坐标压成一维搞

不平行,根据平面向量基本定理得到唯一解

然后用组合数算方案数,对障碍点进行容斥,减去其他障碍点到自己的方案

https://www.cnblogs.com/MaxQAQ/p/16051258.html

code
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cassert>
#include<cstring>
#include<complex>
#include<iostream>
#include<algorithm>
#include<unordered_map>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
int read(){
	int x = 0;bool f = 0; char c = getchar();
	while(!isdigit(c)){f = c == '-'; c = getchar();}
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return f ? -x : x;
}
const int mx = 1e6, mod = 1e9 + 7, maxn = 1e6 + 55;
int qpow(int x, int y){
	int ans = 1;
	for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
	return ans;
}
int fac[maxn], ifac[maxn];
int c(int n, int m){return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;}
int f[2005], f1[2005];
bool vis[2005], flag[2005];
int x, y, k, ax, ay, bx, by;
struct node{int x, y;}d[maxn];
int calc(int x, int y){
	int p, q;
	q = (1ll * ax * y - 1ll * ay * x) / (1ll * ax * by - 1ll * bx * ay);
	if(1ll * q * (1ll * ax * by - 1ll * bx * ay) != (1ll * ax * y - 1ll * ay * x))return 0;
	p = (x - q * bx) / ax;
	if(p * ax != x - q * bx || p < 0 || q < 0) return 0;
	return c(p + q, p);
	
}
int dfs(int x){
	if(vis[x])return f[x];
	vis[x] = 1;
	int res = calc(d[x].x, d[x].y);
	if(res == 0)return f[x] = 0;
	for(int i = 1; i <= k; ++i)if(i != x){
		int nx = d[x].x - d[i].x;
		int ny = d[x].y - d[i].y;
		int v = calc(nx, ny);
		if(v == 0)continue;
		res = (res - 1ll * v * dfs(i) % mod + mod) % mod;
	}
	return f[x] = res;
}
void px(){
	memset(flag,0,sizeof(flag));memset(f1,0,sizeof(f1));
	if(ax * bx < 0){
		printf("-1\n");
		return;
	}
	if(ax < 0){
		x = -x, y = -y, ax = -ax,ay = -ay, bx = -bx, by = -by;
		for(int i = 1; i <= k; ++i) 
			d[i].x = -d[i].x, d[i].y = -d[i].y;
	}
	for(int i = 1; i < k; ++i)if(d[i].x > 0){
		if(1ll * ay * d[i].x == 1ll * d[i].y * ax)flag[d[i].x] = 1;
	}
	f1[0] = 1;
	for(int i = 0; i <= x; ++i)if(!flag[i]){
		f1[i + ax] = (f1[i + ax] + f1[i]) % mod;
		if(ax != bx)f1[i + bx] = (f1[i + bx] + f1[i]) % mod;
	}
	printf("%d\n",f1[x]);
}
void solve(){
	x = read(), y = read(), k = read();
	ax = read(); ay = read(); bx = read(); by = read();
	for(int i = 1; i <= k; ++i)d[i].x = read(), d[i].y = read();
	d[++k] = {x, y};
	if(ax == 0 && ay){
		swap(ax, ay); swap(bx, by); swap(x, y);
		for(int i = 1; i <= k; ++i)swap(d[i].x, d[i].y);
	}
	if(1ll * ay * bx == 1ll * by * ax){
		if(1ll * y * ax == 1ll * ay * x)px();
		else printf("0\n");
		return;
	}
	memset(f,0,sizeof(f));
	memset(vis,0,sizeof(vis));
	printf("%d\n",dfs(k));
}
int main(){
	freopen("knight.in","r",stdin);
	freopen("knight.out","w",stdout);
	fac[0] = ifac[0] = 1; for(int i = 1; i <=mx; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
	ifac[mx] = qpow(fac[mx], mod - 2); for(int i = mx - 1; i > 0; --i)ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
	int t = read(); for(int i = 1; i <= t; ++i)solve();
	return 0;
}

省选模拟之辞旧迎新3

A. 异或矩阵

通过观察性质发现某一位的值是他向上 \(2^x\) 行开始的 \(2^x\) 项的异或

那么得到那一行,前缀异或可以快速得到当前行

发现这个过程可以递归,次数类似快速幂

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

uint read(){
	uint x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}

const int maxn = 3e6 + 5;
uint n, k, a[maxn], tmp[maxn], ans;
void sol(int k){
	if(k == 1)return;
	int h = 1; while(h + h <= k)h += h;
	int l = k - h + 1; sol(l);
	for(int i = 1; i <= n - l + 1; ++i)a[i] ^= a[i - 1];
	for(int i = 1; i <= n - k + 1; ++i)tmp[i] = a[i - 1] ^ a[i + h - 1];
	for(int i = 1; i <= n - k + 1; ++i)a[i] = tmp[i];
}

int main(){
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	n = read(), k = read(); a[1] = read();
	for(int i = 2; i <= n; ++i)a[i] = (1145141 * a[i - 1] + 1919 * i + 810);
	sol(k);
	uint ans = 0;
	for(int i = 1; i <= n - k + 1; ++i){
		ans = (ans + i * (i ^ a[i]));
	}
	printf("%u\n",ans);
	return 0;
}

B. 树

简单容斥题,考场傻逼了,写的相对复杂一些

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}

const int maxn = 3e5 + 55, mod = 998244353;
int n, si[maxn], p2[maxn], ans[maxn];
vector<int>g[maxn];
void add(int &x, int y){x += y; if(x >= mod)x -= mod;}
void dfs(int x, int fa){
	si[x] = 1;
	for(int v : g[x])if(v != fa){
		dfs(v, x); si[x] += si[v];
	}
	int sum = si[x];
	for(int v : g[x])if(v != fa){
		sum -= si[v];
		add(ans[x], 1ll * (p2[si[v]] - 1) * (p2[sum] - 1) % mod);
	}
	add(ans[x], 1);
}
int main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n = read();
	for(int i = 1; i < n; ++i){
		int u = read(), v = read();
		g[u].push_back(v);
		g[v].push_back(u);
	}
	p2[0] = 1; for(int i = 1; i <= n; ++i)p2[i] = (p2[i - 1] + p2[i - 1]) % mod;
	dfs(1, 0);
	for(int i = 1; i <= n; ++i)printf("%d\n",(ans[i] % mod + mod) % mod);
	return 0;
}

C. 黑白树

因为有链加子树加这些,考虑使用树剖

那么问题在于如何维护同色连通块

发现对于在同一同色连通块内的点,他们的异色祖先数量相同

于是在线段树的每个区间都维护与区间内所有点 \(lca\) 异色祖先数量相同的信息

于是在进行 \(2 / 3\) 操作时找到当前连通块深度最小的点,对他对应的区间进行修改与查询

具体的维护 \(cnt[2], ctag[2], mx[2], mtag[2], tag\) 表示区间 \(lca\) 两种颜色祖先数量及标记,与区间 \(lca\) 在同一连通块内的点的最大值及标记,区间加标记

特殊标记只对同一连通块内的区间下传

参考博客

https://www.cnblogs.com/siriehn-nx/p/16061623.html

code
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
int read(){
	int x = 0; bool f = 0; char c = getchar();
	while(!isdigit(c)){f = c == '-'; c = getchar();}
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return f ? -x : x;
}
const int maxn = 200005, inf = 0x3f3f3f3f;
int n, m, col[maxn], val[maxn];
vector<int>g[maxn];
int fa[maxn], dep[maxn], si[maxn], son[maxn], dfn[maxn], dfnr[maxn], top[maxn], id[maxn], tim;
struct seg{
	struct node{int cnt[2], ctag[2], mx[2], mtag[2], tag;}t[maxn << 2 | 1];
	void add_cnt(int x, int col, int val){t[x].cnt[col] += val; t[x].ctag[col] += val;}
	void add_mx(int x, int col, int val){t[x].mx[col] += val; t[x].mtag[col] += val;}
	void add_all(int x, int val){t[x].mx[0] += val; t[x].mx[1] += val; t[x].tag += val;}
	void push_up(int x){
		t[x].mx[0] = max(t[x << 1].cnt[1] == t[x].cnt[1] ? t[x << 1].mx[0] : -inf, t[x << 1 | 1].cnt[1] == t[x].cnt[1] ? t[x << 1 | 1].mx[0] : -inf);
		t[x].mx[1] = max(t[x << 1].cnt[0] == t[x].cnt[0] ? t[x << 1].mx[1] : -inf, t[x << 1 | 1].cnt[0] == t[x].cnt[0] ? t[x << 1 | 1].mx[1] : -inf);
	}
	void push_down(int x){
		int ls = x << 1, rs = x << 1 | 1;
		for(int i = 0; i < 2; ++i){
			if(t[x].ctag[i]){add_cnt(ls, i, t[x].ctag[i]); add_cnt(rs, i, t[x].ctag[i]); t[x].ctag[i] = 0;}
			if(t[x].mtag[i ^ 1]){
				if(t[ls].cnt[i] == t[x].cnt[i])add_mx(ls, i ^ 1, t[x].mtag[i ^ 1]);
				if(t[rs].cnt[i] == t[x].cnt[i])add_mx(rs, i ^ 1, t[x].mtag[i ^ 1]);
				t[x].mtag[i ^ 1] = 0;
			}
		}
		if(t[x].tag){add_all(ls, t[x].tag); add_all(rs, t[x].tag); t[x].tag = 0;}
	}
	void rev(int x, int l, int r, int pos){
		if(l == r){swap(t[x].mx[0], t[x].mx[1]); return;}
		push_down(x); int mid = (l + r) >> 1;
		if(pos <= mid)rev(x << 1, l, mid, pos);
		else rev(x << 1 | 1, mid + 1, r, pos);
		push_up(x);
	}
	void modify_all(int x, int l, int r, int L, int R, int val){
		if(L <= l && r <= R)return add_all(x, val);
		push_down(x); int mid = (l + r) >> 1;
		if(L <= mid)modify_all(x << 1, l, mid, L, R, val);
		if(R > mid)modify_all(x << 1 | 1, mid + 1, r, L, R, val);
		push_up(x);
	}
	void modify_cnt(int x, int l, int r, int L, int R, int col, int val){
		if(L <= l && r <= R)return add_cnt(x, col, val);
		push_down(x); int mid = (l + r) >> 1;
		if(L <= mid)modify_cnt(x << 1, l, mid, L, R, col, val);
		if(R > mid)modify_cnt(x << 1 | 1, mid + 1, r, L, R, col, val);
		push_up(x);
	}
	void modify_mx(int x, int l, int r, int L, int R, int col, int cnt, int val){
		if(t[x].cnt[col ^ 1] > cnt)return;
		if(L <= l && r <= R)return add_mx(x, col, val);
		push_down(x); int mid = (l + r) >> 1;
		if(L <= mid)modify_mx(x << 1, l, mid, L, R, col, cnt, val);
		if(R > mid)modify_mx(x << 1 | 1, mid + 1, r, L, R, col, cnt, val);
		push_up(x);
	}
	int query_mx(int x, int l, int r, int L, int R, int col, int cnt){
		if(t[x].cnt[col ^ 1] > cnt)return -inf;
		if(L <= l && r <= R)return t[x].mx[col];
		push_down(x); int mid = (l + r) >> 1, ans = -inf;
		if(L <= mid)ans = max(ans, query_mx(x << 1, l, mid, L, R, col, cnt));
		if(R > mid)ans = max(ans, query_mx(x << 1 | 1, mid + 1, r, L, R, col, cnt));
		return ans;
	}
	int query_cnt(int x, int l, int r, int pos, int col){
		if(l == r)return t[x].cnt[col];
		push_down(x); int mid = (l + r) >> 1;
		if(pos <= mid)return query_cnt(x << 1, l, mid, pos, col);
		else return query_cnt(x << 1 | 1, mid + 1, r, pos, col);
	}
}T;
void dfs1(int x){
	si[x] = 1;
	for(int v : g[x])if(v != fa[x]){
		fa[v] = x; dep[v] = dep[x] + 1;
		dfs1(v); si[x] += si[v];
		if(si[son[x]] < si[v])son[x] = v;
	}
}
set<pii>s[2][maxn];
void dfs2(int x, int tp){
	id[dfn[x] = ++tim] = x; top[x] = tp; 
	if(son[x])dfs2(son[x], tp);
	for(int v : g[x])if(v != fa[x] && v != son[x])dfs2(v, v);
	dfnr[x] = tim;
}
int find(int x){
	pii res; res.first = dep[x]; res.second = x; int c = !col[x];
	for(; x; x = fa[top[x]]){
		auto it = s[c][top[x]].upper_bound({dep[x], inf});
		if(it != s[c][top[x]].begin()){
			--it;
			if((*it).first + 1 < res.first)res = {1 + (*it).first, son[(*it).second]};
			break;
		}
		res = {dep[top[x]], top[x]}; 
	}
	return res.second;
}
void upd(int u, int v, int val){
	while(top[u] != top[v]){
		if(dep[top[u]] < dep[top[v]])swap(u, v);
		T.modify_all(1, 1, n, dfn[top[u]], dfn[u], val);
		u = fa[top[u]];
	}
	if(dep[u] > dep[v])swap(u, v);
	T.modify_all(1, 1, n, dfn[u], dfn[v], val);
}
int main(){
	freopen("astill.in","r",stdin);
	freopen("astill.out","w",stdout);
	n = read(), m = read();
	for(int i = 1; i < n; ++i){
		int u = read(), v = read();
		g[u].push_back(v); g[v].push_back(u);
	}
	for(int i = 1; i <= n; ++i)col[i] = read();
	for(int i = 1; i <= n; ++i)val[i] = read();
	dfs1(1); dfs2(1, 1);
	for(int i = 1; i <= n; ++i)s[col[i]][top[i]].insert({dep[i], i});
	for(int i = 1; i <= n; ++i)T.modify_cnt(1, 1, n, dfn[i], dfnr[i], col[i], 1);
	for(int i = 1; i <= n; ++i)T.modify_all(1, 1, n, dfn[i], dfn[i], val[i]);
	for(int i = 1; i <= m; ++i){
		int opt = read(), x = read();
		if(opt == 1){
			T.modify_cnt(1, 1, n, dfn[x], dfnr[x], col[x], -1);
			s[col[x]][top[x]].erase({dep[x], x});
			col[x] ^= 1;
			s[col[x]][top[x]].insert({dep[x], x});
			T.rev(1, 1, n, dfn[x]);
			T.modify_cnt(1, 1, n, dfn[x], dfnr[x], col[x], 1);
		}else if(opt == 2){
			x = find(x);
			T.modify_mx(1, 1, n, dfn[x], dfnr[x], col[x], T.query_cnt(1, 1, n, dfn[x], !col[x]), read());
		}else if(opt == 3){
			x = find(x);
			printf("%d\n",T.query_mx(1, 1, n, dfn[x], dfnr[x], col[x], T.query_cnt(1, 1, n, dfn[x], !col[x])));
		}else if(opt == 4){int y = read(); upd(x, y, read());
		}else T.modify_all(1, 1, n, dfn[x], dfnr[x], read());
	}
	return 0;
}

省选模拟之辞旧迎新4

A. 逃离藏宝洞

随机走一边,查询,不对就退回去

错误两次就能确定正确方向,此时直接走上去

询问次数远小于步数的随机一次走 \(50\) 步左右,期望下正确

code
#include"escape.h"
#include<bits/stdc++.h>
using namespace std;

typedef unsigned long long  ull;

mt19937 rd((ull)(new char) * (ull)(new char));

int sint(int l, int r){return uniform_int_distribution<>(l, r)(rd);}

int rdr(int from){
	int t = sint(0, 2);
	while(t == from)t = sint(0, 2);
	return t;
}
int res(int x, int y){
	if(x > y)swap(x, y);
	if(x)return 0;
	if(y == 2)return 1;
	return 2;
}

void know1(int dep, int from){
	int t1 = rdr(from), d1;
	move(t1); d1 = query();
	if(d1 == dep - 1){
		move(t1); 
		move(t1 = res(from, t1));
	}
	know1(dep + 1, t1);
}
void solve1(){
	int dep, ndep, tt = rdr(-1);
	dep = query();
	move(tt);
	ndep = query();
	if(ndep ==  dep - 1)move(tt), know1(dep, tt);
	else know1(dep + 1, tt);
}

int l[100005], lim;
void move50(int from){
	l[0] = from;
	for(int i = 1; i <= lim; ++i)l[i] = rdr(l[i - 1]);
	for(int i = 1; i <= lim; ++i)move(l[i]);
}
void ret(int x){
	for(int i = lim; i > x; --i)move(l[i]);
}
void know1_50(int dep, int from){
	int ndep;
	move50(from);
	ndep = query();
	int cro = (lim - (dep - ndep)) / 2;
	ret(cro);
	if(cro == 50)know1_50(dep + 1, l[50]);
	if(cro == 0){
		move(res(from, l[1]));
		know1_50(dep + 1, res(from, l[1]));
	}else{
		dep = dep + cro;
		move(res(l[cro], l[cro + 1]));
		know1_50(dep + 1, res(l[cro], l[cro + 1]));
	}
}
void solve2(){
	int dep, ndep; dep = query();
	move50(-1); ndep = query();
	int cro = (lim - (dep - ndep)) / 2;
	ret(cro);
	dep = dep + cro;
	know1_50(dep, l[cro]);
}
void escape(int lm, int lq){
	lim = 50;
	if(lm == 1e7 && lq != 100002)solve2();
	else solve1();
}

B. 序列划分

首先 \(DP\) 枚举最后一段

\(f_i = \sum _{j < i} f_j mex_{j, i}\)

套路的用线段树维护 \(mex\)

转换 \(DP\) 为刷表法

\(f_i mex_{i, j}-> [j > i] f_j\)

那么我们有区间覆盖和区间乘对应项两种操作,

首先确定一个顺序,由于区间覆盖会影响对应项,于是他后做

那么考虑如何合并标记,当区间乘发现该区间覆盖过,其实可以转换成加上定值

于是新维护一个加法标记即可

初始化令叶结点区间覆盖标记存在,那么下传标记就不用特判了

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c)) c = getchar();
	do{x = x * 10 +  (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}
const int maxn = 1e6 + 55, mod = 998244353;
int n, a[maxn], mex[maxn], nxt[maxn], pos[maxn];
int f[maxn];
bool vis[maxn];
void add(int &x, int y){x += y; if(x >= mod) x -= mod;}

struct seg{
	struct node{
		int val, mex, mul, tag;
	}t[maxn << 2 | 1];
	void push_up(int x){t[x].mex = max(t[x << 1].mex, t[x << 1 | 1].mex);}
	void push_down(int x){
		int ls = x << 1, rs = x << 1 | 1;
		if(t[x].mul){
			if(t[ls].tag != -1)add(t[ls].val, 1ll * t[x].mul * t[ls].tag % mod);
			else add(t[ls].mul, t[x].mul);
			if(t[rs].tag != -1)add(t[rs].val, 1ll * t[x].mul * t[rs].tag % mod);
			else add(t[rs].mul, t[x].mul);
			t[x].mul = 0;
		}
		if(t[x].val){
			add(t[ls].val, t[x].val);
			add(t[rs].val, t[x].val);
			t[x].val = 0;
		}
		if(t[x].tag != -1){
			t[ls].tag = t[rs].tag = t[x].tag;
			t[ls].mex = t[rs].mex = t[x].tag;
			t[x].tag = -1;
		}
	}
	void build(int x, int l, int r){
		t[x].tag = -1;
		if(l == r){t[x].mex = t[x].tag = mex[l]; return;}
		int mid = (l + r) >> 1;
		build(x << 1, l, mid);
		build(x << 1 | 1, mid + 1, r);
		push_up(x);
	}
	void modify_val(int x, int l, int r, int L, int R, int val){
		if(L <= l && r <= R){
			if(t[x].tag != -1) add(t[x].val, 1ll * t[x].tag * val % mod);
			else add(t[x].mul, val);
			return;
		}
		push_down(x); int mid = (l + r) >> 1;
		if(L <= mid)modify_val(x << 1, l, mid, L, R, val);
		if(R > mid)modify_val(x << 1 | 1, mid + 1, r, L, R, val);
	}
	void modify_mex(int x, int l, int r, int L, int R, int mex){
		if(L <= l && r <= R){
			t[x].mex = t[x].tag = mex;
			return;
		}
		push_down(x); int mid = (l + r) >> 1;
		if(L <= mid)modify_mex(x << 1, l, mid, L, R, mex);
		if(R > mid)modify_mex(x << 1 | 1, mid + 1, r, L, R, mex);
		push_up(x);
	}
	int find(int x, int l, int r, int val){
		if(l == r)return l + (t[x].mex <= val);
		push_down(x); int mid = (l + r) >> 1;
		if(t[x << 1].mex > val)return find(x << 1, l, mid, val);
		else return find(x << 1 | 1, mid + 1, r, val);
	}
	int query(int x, int l, int r, int pos){
		if(l == r)return t[x].val;
		push_down(x); int mid = (l + r) >> 1;
		if(pos <= mid)return query(x << 1, l, mid, pos);
		else return query(x << 1 | 1, mid + 1, r, pos);
	}
}T;

int main(){
	freopen("divide.in","r",stdin);
	freopen("divide.out","w",stdout);
	n = read(); for(int i = 1; i <= n; ++i)a[i] = read();
	for(int i = 0; i <= n; ++i)pos[i] = n + 1;
	for(int i = n; i >= 1; --i)if(a[i] <= n){
		nxt[i] = pos[a[i]]; pos[a[i]] = i;
	}
	for(int i = 1; i <= n; ++i){
		mex[i] = mex[i - 1];
		if(a[i] <= n){
			vis[a[i]] = true;
			while(vis[mex[i]])++mex[i];
		}
	}
	T.build(1, 1, n); T.modify_val(1, 1, n, 1, n, 1);
	for(int i = 1; i < n; ++i){
		if(a[i] <= n){
			int pl = T.find(1, 1, n, a[i]);
			if(pl < nxt[i])T.modify_mex(1, 1, n, pl, nxt[i] - 1, a[i]);
		}
		T.modify_val(1, 1, n, i + 1, n, T.query(1, 1, n, i));
	}
	printf("%d\n",T.query(1, 1, n, n));
	return 0;
}

C. 重排列

https://www.luogu.com.cn/problem/AT_agc010_e

把不互质的两个数连边,形成一个图

操作的实质是先手对图定向,后手进行字典序最大的拓扑排序

那么先手的最优策略就是对每个连通块定向时,贪心的从最小点开始,按照顺序扫描边,优先走字典序小的边

后手策略就是用大根堆进行拓扑排序

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c)) c = getchar();
	do{x = x * 10 +  (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}
const int maxn = 2005;
bool vis[maxn];
int n, a[maxn], deg[maxn];
vector<int>g[maxn];
priority_queue<int>q;
void dfs(int x){
	vis[x] = true;
	for(int i = 1; i <= n; ++i)
		if(!vis[i] && __gcd(a[i], a[x]) != 1){
			++deg[i]; g[x].push_back(i); dfs(i);
		}
}
int main(){
	freopen("permutation.in","r",stdin);
	freopen("permutation.out","w",stdout);
	n = read(); for(int i = 1; i <= n; ++i)a[i] = read();
	sort(a + 1, a + n + 1);
	for(int i = 1; i <= n; ++i)if(!vis[i])dfs(i);
	for(int i = 1; i <= n; ++i)if(deg[i] == 0)q.push(i);
	while(!q.empty()){
		int x = q.top(); q.pop();
		printf("%d ",a[x]);
		for(int v : g[x])q.push(v);
	}
	return 0;
}

标签:dep,系列,省选,long,int,maxn,return,include,模拟
From: https://www.cnblogs.com/Chencgy/p/17069201.html

相关文章