省选模拟 19/11/05

42 篇文章 0 订阅
19 篇文章 0 订阅

黑白划分
最后答案的个数就是非纯色正方形的个数
考虑容斥,用总的减去纯色的
发现对每一个纯色的都要减去它覆盖的四个的贡献,而这样减正好能减完,令 f ( i ) f(i) f(i) 表示边长为 2 i 2^i 2i 的个数
a n s = ∑ i = 0 n ( 2 n − i ) 2 − 4 ∗ f ( i ) ∗ [ i > 0 ] ans=\sum_{i=0}^n(2^{n-i})^2-4*f(i)*[i>0] ans=i=0n(2ni)24f(i)[i>0]
然后发现两个维度是独立的,我们对两个维度分别求出它的连续纯色区间个数,乘起来就是答案
分离两个维度的考虑巧妙

#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
}
cs int N = 21, M = 1 << 20 | 5;
typedef long long ll;
int n, q, S, lg[M];
struct Segmentree{
	int sum[M << 2], ct[N];
	#define mid ((l+r)>>1)
	void pushup(int x, int l, int r){
		int pre = sum[x];
		sum[x] = sum[x<<1] + sum[x<<1|1];
		if((pre == 0 && sum[x] == 1) || (pre == r-l+1 && sum[x] == r-l)) --ct[lg[r-l+1]];
		else if((pre == 1 && sum[x] == 0) || (pre == r-l && sum[x] == r-l+1)) ++ct[lg[r-l+1]];
	}
	void build(int x, int l, int r){
		ct[lg[r - l + 1]]++;
		if(l == r) return; build(x<<1, l, mid); build(x<<1|1, mid+1, r);
	}
	void modify(int x, int l, int r, int p){
		if(l == r){ sum[x] ^= 1; return; }
		if(p <= mid) modify(x<<1, l, mid, p);
		else modify(x<<1|1, mid+1, r, p);
		pushup(x, l, r);
	}
}seg[2];
int main(){
	n = read(), q = read(); S = 1 << n;
	for(int i = 2; i <= S; i++) lg[i] = lg[i>>1] + 1; 
	seg[0].build(1, 1, S);
	seg[1].build(1, 1, S);
	while(q--){
		int op = read(), x = read();
		seg[op].modify(1, 1, S, x);
		ll ans = 0;
		for(int i = 0; i <= n; i++){
			ll ret = 1ll * seg[0].ct[i] * seg[1].ct[i];
			ans += 1ll << ((n - i) << 1);
			if(i) ans -= ret << 2;
		} cout << ans << '\n';
	} return 0;
}

1959 年式中型坦克
首先暴力的做法是两边分别按 y y y 排序,每次枚举两个点,删除两边的后缀判断联不联通
发现双指针维护即可,先把第一个序列插入,然后每次删除一个点以及相连的边
下面的序列插入,直到联通
发现可以用 l c t lct lct 维护,但有一个问题是可能形成环,这时候我们需要删掉环上 y u y_u yu 最大的也就是应该被最先退掉的点,需要维护一个链上最大,拆边为点即可
然后还需要支持判断有没有联通,也就是一个连通块的关键点的个数或者权值之和
l c t lct lct 维护虚子树信息即可

#include<bits/stdc++.h>
#define cs const
#define y1 y_1
#define y2 y_2
#define re register
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
}
cs int N = 7e5 + 5;
typedef long long ll;
ll gcd(ll a, ll b){ return !b ? a : gcd(b, a % b); }
int n, m1, m2;
int y1[N], y2[N], b[N];
vector<int> e1[N], e2[N];
vector<int> nd1[N], nd2[N];
int tot, ec, ct1, ct2;
struct edge{ int u, v; } e[N];
int pos[N], p1[N], p2[N];
int val[N], tim[N];
#define pb push_back
namespace LCT{
	int ch[N][2], fa[N], sum[N], sub[N], mx[N]; // sub 维护虚子树  
	bool rev[N];
	#define ls ch[x][0]
	#define rs ch[x][1]
	bool isr(int x){return ch[fa[x]][0] != x && ch[fa[x]][1] != x;}
	void pushrev(int x){ if(!x) return; rev[x] ^= 1; swap(ls, rs); }
	void pushdown(int x){ if(rev[x]) pushrev(ls), pushrev(rs), rev[x] = 0; }
	void pushup(int x){
		sum[x] = sum[ls] + sum[rs] + val[x] + sub[x]; 
		mx[x] = x;
		if(tim[mx[ls]] > tim[mx[x]]) mx[x] = mx[ls];
		if(tim[mx[rs]] > tim[mx[x]]) mx[x] = mx[rs];
	}
	void pushpath(int x){ if(!isr(x)) pushpath(fa[x]); pushdown(x); } 
	void rotate(int x){
		int y = fa[x], z = fa[y], k = ch[y][1] == x;
		if(!isr(y)) ch[z][ch[z][1] == y] = x; fa[x] = z; 
		ch[y][k] = ch[x][k^1]; fa[ch[x][k^1]] = y;
		ch[x][k^1] = y; fa[y] = x; pushup(y); pushup(x);
	}
	void splay(int x){
		pushpath(x);
		while(!isr(x)){
			int y = fa[x], z = fa[y];
			if(!isr(y)) rotate((ch[y][0] == x) ^ (ch[z][0] == y) ? x : y);
			rotate(x);
		} pushup(x);
	} 
	void access(int x){
		for(int y = 0; x; y = x, x = fa[x]){
			splay(x); if(rs) sub[x] += sum[rs];
			if(y) sub[x] -= sum[y]; rs = y;
			pushup(x);
		}
	}
	int findrt(int x){access(x); splay(x); pushdown(x); while(ls) x = ls, pushdown(x); return x; }
	void mkroot(int x){ access(x); splay(x); pushrev(x); } 
	bool in(int x, int y){mkroot(x); return findrt(y) == x; }
	void link(int x, int y){ mkroot(x); access(y); splay(y); fa[x] = y; sub[y] += sum[x]; pushup(y); }
	void cut(int x, int y){ mkroot(x); access(y); splay(y); fa[x] = ch[y][0] = 0; pushup(x); pushup(y); }
	int qsz(int x){ access(x); splay(x);  return sum[x]; }
	int find(int x, int y){ mkroot(x); access(y); splay(y); return mx[y]; } 
}	
int main(){
	n = read(), m1 = read(), m2 = read();
	tot = n + m1 + n + m2;
	for(int i = 1; i <= m1; i++) p1[i] = ++tot;
	for(int i = 1; i <= m2; i++) p2[i] = ++tot;
	for(int i = 1; i <= n; i++) pos[i] = ++tot, val[tot] = 1;
	for(int i = 1; i <= m1; i++) y1[i] = read(), b[i] = y1[i] = read();
	
	sort(b + 1, b + m1 + 1); ct1 = unique(b + 1, b + m1 + 1) - (b + 1);
	for(int i = 1; i <= m1; i++){
		y1[i] = lower_bound(b + 1, b + ct1 + 1, y1[i]) - b;
		nd1[y1[i]].pb(i);
	}
	
	for(int i = 1; i < n + m1; i++){
		int t = read(), u = read(), v = read();
		if(t == 1){
			e[++ec] = (edge){ pos[u], p1[v] };
			e1[v].pb(ec); tim[ec] = y1[v];
			LCT::link(ec, pos[u]);
			LCT::link(ec, p1[v]);
		} else{
			e[++ec] = (edge){ p1[u], p1[v] };
			if(y1[u] > y1[v]) e1[u].pb(ec), tim[ec] = y1[u];
			else e1[v].pb(ec), tim[ec] = y1[v];
			LCT::link(ec, p1[u]);
			LCT::link(ec, p1[v]);
		}
	}
	for(int i = 1; i <= m2; i++) y2[i] = read(), b[i] = y2[i] = abs(read());
	sort(b + 1, b + m2 + 1); ct2 = unique(b + 1, b + m2 + 1) - (b + 1);
	for(int i = 1; i <= m2; i++){
		y2[i] = lower_bound(b + 1, b + ct2 + 1, y2[i]) - b;
		nd2[y2[i]].pb(i);
	}
	for(int i = 1; i < n + m2; i++){
		int t = read(), u = read(), v = read();
		if(t == 1){
			e[++ec] = (edge){ pos[u], p2[v] };
			e2[v].pb(ec);  
		} else{
			e[++ec] = (edge){ p2[u], p2[v] };
			if(y2[u] > y2[v]) e2[u].pb(ec);
			else e2[v].pb(ec);
		}
	} 
	ll ans = 0, all = (ll)m1 * m2;
	for(int i = ct1, j = 1, now = 0; i >= 1; i--){
		for(int o = 0; o < nd1[i].size(); o++){
			int u = nd1[i][o];
			for(int k = 0; k < e1[u].size(); k++){
				int nx = e1[u][k];
				if(LCT::in(e[nx].u, nx)) LCT::cut(e[nx].u, nx);
				if(LCT::in(e[nx].v, nx)) LCT::cut(e[nx].v, nx);
			}
		}
		while(j <= ct2 && LCT::qsz(pos[1]) < n){
			for(int o = 0; o < nd2[j].size(); o++){
				int u = nd2[j][o];
				for(int k = 0; k < e2[u].size(); k++){
					int nx = e2[u][k];
					if(LCT::in(e[nx].u, e[nx].v)){
						int p = LCT::find(e[nx].u, e[nx].v);	
						LCT::cut(p, e[p].u); 
						LCT::cut(p, e[p].v);
					}
					LCT::link(nx, e[nx].u);
					LCT::link(nx, e[nx].v);
				} 
			} now += nd2[j++].size();
		} ans += 1ll * nd1[i].size() * (m2 - now);
	} if(ans == 0) puts("0");
	else if(ans == all) puts("1");
	else{
		ll g = gcd(ans, all);
		cout << ans / g << "/" << all / g;
	} return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值