「NOI2023」方格染色 + 贸易

666,还有合订版。

方格染色

我们思考一个事情,就是假如没有斜着染的,就是比较套路的扫描线,具体一点就是先把横着染和竖着染的操作合并(也就是处理相同种类的相交),然后按照某一位来排序,处理横着和竖着的相交部分就行了,这个可以线段树来维护。

然后现在有斜着的线,我们还是先合并斜着的线,然后我们通过暴力判断每个横着的线与竖着的线是否相交,同时用 set 存相交点的位置就可以了,这个是为了避免算重。

这个题就做完了。

点击查看代码
//奇跡を信じて,願いを叶えて
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define uint unsigned long long
#define Air
namespace io{
	inline int read(){
		int f = 1, t = 0; char ch = getchar();
		while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();}
		while(ch >= '0' && ch <= '9'){t = t * 10 + ch - '0'; ch = getchar();}
		return t * f;
	}
	inline void write(int x){
		if(x < 0){putchar('-'); x = -x;}
		if(x >= 10){write(x / 10);}
		putchar(x % 10 + '0');
	}
}
using namespace io;
int n, m, q;
const int N = 2e5 + 10;
vector<int>e[N];
vector<int> lx, ly;
set<pair<int, int> > st[10];
struct Data{
	int xl, yl;
	int xr, yr;
};
vector<Data>dat[4], tru[4];
void judge(int id, Data dat){
	Data tmp = tru[3][id]; 	
	if(dat.xl == dat.xr){
		if(tmp.xl > dat.xl || tmp.xr < dat.xl) return ;
		int val = tmp.yl + dat.xl - tmp.xl;
		if(dat.yl > val || dat.yr < val) return ;
		st[id].insert({dat.xl, val});
	}
	else{
		if(tmp.yl > dat.yl || tmp.yr < dat.yl) return ;
		int val = tmp.xl + dat.yl - tmp.yl;
		if(dat.xl > val || dat.xr < val) return ;
		st[id].insert({val, dat.yl});
	}
}
struct Quest{
	int op;
	int tx, ty;
	int dep;
	friend bool operator < (Quest x, Quest y){
		return (x.dep != y.dep) ? (x.dep < y.dep) : (x.op < y.op);
	}
};
vector<Quest> que;
struct Segment{
	int l, r;
	int dat;
}seg[N * 4];
void build(int p, int l, int r){
	seg[p].l = l;
	seg[p].r = r;
	if(seg[p].l == seg[p].r){
		return ;
	}
	int mid = (l + r) >> 1;
	build(p * 2, l, mid);
	build(p * 2 + 1, mid + 1, r);
}
void change(int p, int l, int r, int v){
	if(seg[p].l >= l && seg[p].r <= r){
		seg[p].dat += v;
		return ;
	}
	int mid = (seg[p].l + seg[p].r) >> 1;
	if(l <= mid){
		change(p * 2, l, r, v);
	}
	if(r > mid){
		change(p * 2 + 1, l, r, v);
	}
}
int ask(int p, int x){
	if(seg[p].l == seg[p].r){
		return seg[p].dat;
	}
	int mid = (seg[p].l + seg[p].r) >> 1;
	if(x <= mid){
		return ask(p * 2, x) + seg[p].dat;
	}
	else{
		return ask(p * 2 + 1, x) + seg[p].dat;
	}
}
signed main() {
#ifndef Air
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);
#endif
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	read();
	lx.push_back(-1);
	ly.push_back(-1);
	n = read(); m = read();
	q = read();
	for(int i = 1; i <= q; i++){
		int op = read();
		dat[op].push_back({read(), read(), read(), read()});
		lx.push_back(dat[op].back().xl);
		lx.push_back(dat[op].back().xr);
		ly.push_back(dat[op].back().yl);
		ly.push_back(dat[op].back().yr);
	}
	sort(lx.begin(), lx.end()); lx.erase(unique(lx.begin(), lx.end()), lx.end());
	sort(ly.begin(), ly.end()); ly.erase(unique(ly.begin(), ly.end()), ly.end());
	sort(dat[1].begin(), dat[1].end(), [](Data x, Data y){
		return (x.yl != y.yl) ? (x.yl < y.yl) : (x.xl < y.xl);
	});
	sort(dat[2].begin(), dat[2].end(), [](Data x, Data y){
		return (x.xl != y.xl) ? (x.xl < y.xl) : (x.yl < y.yl);
	});
	sort(dat[3].begin(), dat[3].end(), [](Data x, Data y){
		return (x.xl - x.yl != y.xl - y.yl) ? (x.xl - x.yl < y.xl - y.yl) : (x.xl < y.xl);
	});
	for(int i = 0; i < dat[3].size(); i++){
		int j = i, mx = dat[3][i].xr;
		while(j + 1 < dat[3].size() && dat[3][j + 1].xl - dat[3][j + 1].yl == dat[3][i].xl - dat[3][i].yl && dat[3][j + 1].xl <= mx + 1){
			j++;
			mx = max(mx, dat[3][j].xr);
		}
		tru[3].push_back({dat[3][i].xl, dat[3][i].yl, mx, mx - dat[3][i].xl + dat[3][i].yl});
		i = j;
	}
	int ans = 0;
	for(int i = 0; i < dat[1].size(); i++){
		int j = i, mx = dat[1][i].xr;
		while(j + 1 < dat[1].size() && dat[1][j + 1].yl == dat[1][i].yl && dat[1][j + 1].xl <= mx + 1){
			j++;
			// cerr << " ??" << mxx << ' ' << 
			mx = max(mx, dat[1][j].xr);
		}
		Data tmp = {dat[1][i].xl, dat[1][i].yl, mx, dat[1][i].yl};
		// cerr << dat[1][i].xl << ' ' << mx << ' ' << dat[1][i].yl << '\n';
		for(int k = 0; k < dat[3].size(); k++){
			judge(k, tmp);
		}
		ans += mx - dat[1][i].xl + 1;
		que.push_back({1, tmp.xl, tmp.xr, tmp.yl});
		i = j;
	}
	for(int i = 0; i < dat[2].size(); i++){
		int j = i, mx = dat[2][i].yr;
		while(j + 1 < dat[2].size() && dat[2][j + 1].xl == dat[2][i].xl && dat[2][j + 1].yl <= mx + 1){
			j++;
			mx = max(mx, dat[2][j].yr);
		}
		Data tmp = {dat[2][i].xl, dat[2][i].yl, dat[2][i].xl, mx};
		// cerr << dat[2][i].yl << ' ' << mx << ' ' << dat[2][i].xl << '\n';
		for(int k = 0; k < dat[3].size(); k++){
			judge(k, tmp);
		}
		// cerr << i << ' ' << j << '\n';
		ans += mx - dat[2][i].yl + 1;
		que.push_back({2, tmp.xl, 0, tmp.yl - 1});
		que.push_back({3, tmp.xl, 0, tmp.yr});
		i = j;
	}
	sort(que.begin(), que.end());
	build(1, 1, lx.size());
	for(auto y: que){
		if(y.op == 1){
			y.tx = lower_bound(lx.begin(), lx.end(), y.tx) - lx.begin();	
			y.ty = lower_bound(lx.begin(), lx.end(), y.ty) - lx.begin();
			// cerr << y.tx << ' ' << y.ty << '\n';
			change(1, y.tx, y.ty, 1);	
		}
		if(y.op == 2){
			y.tx = lower_bound(lx.begin(), lx.end(), y.tx) - lx.begin();	
			// cerr << y.tx << ' '<< '\n';
			ans += ask(1, y.tx);
			// cerr << -ask(1, y.tx) << '\n';
		}
		if(y.op == 3){
			y.tx = lower_bound(lx.begin(), lx.end(), y.tx) - lx.begin();	
			// cerr << y.tx << ' ' << '\n';
			ans -= ask(1, y.tx);
			// cerr << +ask(1, y.tx) << '\n';
		}
	}
	for(int i = 0; i < tru[3].size(); i++){
		ans -= st[i].size();
		// cerr << st[i].size() << '\n';
		ans += tru[3][i].xr - tru[3][i].xl + 1;
	}
	cout << ans;
	return 0;
}

贸易

我们先思考一个事情,就是我们思考一个点答案的构成,发现就两种:直接往下走的,和先往上走几步再往下走的。

然后我们发现第二种是可以继续往上递归的,也就是我们现在只需要求出来每个点直接往下走的答案,这个可以通过在子树里面跑任何一种最短路算法来实现,我写的是 dijkstra。

那么每个点的答案就是一直往上面并,我们利用 dfs 来计算这个过程,大概需要维护一个全局加和单点取最小值和全局求和还有撤销的一个东西,这个打标记就行了。

点击查看代码
//奇跡を信じて,願いを叶えて
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define uint unsigned long long
#define Air
namespace io{
	inline int read(){
		int f = 1, t = 0; char ch = getchar();
		while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();}
		while(ch >= '0' && ch <= '9'){t = t * 10 + ch - '0'; ch = getchar();}
		return t * f;
	}
	inline void write(int x){
		if(x < 0){putchar('-'); x = -x;}
		if(x >= 10){write(x / 10);}
		putchar(x % 10 + '0');
	}
}
using namespace io;
int n, m;
const int N = 262154;
vector<int>e[N], v[N];
int val[N];
vector<int> son[N];
int dis[N];
bool vis[N];
struct Data{
	int now, val;
	friend bool operator < (Data x, Data y){
		return x.val > y.val;
	}
};
priority_queue<Data> q;
void dijk(int rt){
	for(auto y: son[rt]){
		dis[y] = 1e18;
		vis[y] = 0;
	}
	dis[rt] = 0;
	q.push({rt, 0});
	while(q.size()){
		int now = q.top().now;
		q.pop();
		if(vis[now]) continue;
		vis[now] = 1;
		for(int i = 0; i < e[now].size(); i++){
			int y = e[now][i], z = v[now][i];
			if(dis[y] > dis[now] + z){
				dis[y] = dis[now] + z;
				q.push({y, dis[y]});
			}
		}
	}
}
const int MOD = 998244353;
struct Node{
	int a[N];
	bool flag[N];
	int sum;
	int tot;
	int laz;
	struct Roll{
		int op, id, val;
		int dep;
	};
	stack<Roll> st;
	void roll(int val){
		while(st.size() && st.top().dep == val){
			if(st.top().op == 1){
				a[st.top().id] = st.top().val;
			}
			if(st.top().op == 2){
				flag[st.top().id] = st.top().val;
			}
			if(st.top().op == 3){
				sum = st.top().val;
			}
			if(st.top().op == 4){
				tot = st.top().val;
			}
			if(st.top().op == 5){
				laz = st.top().val;
			}
			st.pop();
		}
	}
	int get(){
		return sum + laz * tot % MOD;
	}
	void upd(int rt){
		if(rt != 1){
			st.push({5, 0, laz, rt});
			laz += v[rt][0];
		}
		for(auto y: son[rt]){
			if(dis[y] == 1e18) continue;
			if(!flag[y]){
				st.push({1, y, 0, rt});
				st.push({2, y, 0, rt});
				st.push({3, 0, sum, rt});
				st.push({4, 0, tot, rt});
				flag[y] = 1;
				tot ++;
				a[y] = dis[y] - laz;
				sum += a[y];
			}
			else{
				st.push({1, y, a[y], rt});
				st.push({3, 0, sum, rt});
				sum -= a[y];
				a[y] = min(a[y], dis[y] - laz);
				sum += a[y];
			}
		}
	}
}ds;

int ans = 0;
void dfs(int now){
	// cerr << now << '\n';
	if(now > n) return ;
	dijk(now);
	ds.upd(now);
	// cerr << ds.tot << '\n';
	ans += ds.get(); ans %= MOD;
	dfs(now * 2);
	dfs(now * 2 + 1);
	ds.roll(now);
}
signed main() {
#ifndef Air
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);
#endif
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	n = (1ll << read()) - 1;
	m = read();
	for(int i = 2; i <= n; i++){
		e[i].push_back(i / 2);
		v[i].push_back(read());
	}
	for(int i = 1; i <= m; i++){
		int x = read(), y = read(), z = read();
		e[x].push_back(y);
		v[x].push_back(z);
	}
	for(int i = 1; i <= n; i++){
		int now = i;
		while(now){
			son[now].push_back(i);
			now >>= 1;
		}
	}
	dfs(1);
	cout << ans;
	return 0;
}
posted @ 2026-06-16 14:59  Air2011  阅读(8)  评论(0)    收藏  举报