20230527 板子 板子和板子

P1038 [NOIP2003 提高组] 神经网络
发现对于 i 我们必须知道 i 之前所有 j 的值 想到拓扑
然后发现根据题意 必然是一个 DAG 图 直接做就行
code:

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

const int N = 1e5 + 0721 ;
int head[N] , nxt[N] , to[N] , w[N] , cnt ;
int c[N] , v[N] ;
bool sr[N] ;
int rd[N] , cd[N] , topo[N] , top ;
int n , p ;

struct node{
	int id , c ;
}a[N];

bool cmp( node x , node y ){
	return x.id < y.id ;
}

void cmb( int x , int y , int z ){
	to[++cnt] = y ;
	w[cnt] = z ;
	nxt[cnt] = head[x] ;
	head[x] = cnt ;
	rd[y]++ , cd[x]++ ;
}

int main () {
	
	
	scanf("%d%d" ,&n ,&p ) ;
	for( int i = 1 ; i <= n ; ++i )
	scanf("%d%d" ,&c[i] ,&v[i] ) ;
	
	for( int i = 1 ; i <= p ; ++i ){
		int x , y , z ;
		scanf("%d%d%d" ,&x ,&y ,&z ) ;
		cmb( x , y , z ) ;
	}
	
	for( int i = 1 ; i <= n ; ++i ){
		if( rd[i] == 0 )
		topo[++top] = i , sr[i] = 1 ;
	}
	
	for( int i = 1 ; i <= top ; ++i ){
		int x = topo[i] ;
		for( int j = head[x] ; j ; j = nxt[j] ){
			int y = to[j] ;
			rd[y]-- ;
			if( rd[y] == 0 )
			topo[++top] = y ;
		}
	}
	
	for( int i = 1 ; i <= top ; ++i ){
		int x = topo[i] ;
		if( !sr[x] )
		c[x] -= v[x] ;
		for( int j = head[x] ; j ; j = nxt[j] ){
			int y = to[j] ;
			if( c[x] > 0 ){
				c[y] += c[x] * w[j] ;
//				cout<<y<<" "<<c[y]<<endl ;
			}
		}
	}
	
	top = 0 ;
	for( int i = 1 ; i <= n ; ++i ){
		if( cd[i] == 0 && c[i] > 0 ){
			a[++top].id = i ;
			a[top].c = c[i] ;
		}
	}
	
	
	
	sort( a+1 , a+1+top , cmp ) ;
	
	if( top == 0 )
	printf("NULL") ;
	else{
		for( int i = 1 ; i <= top ; ++i )
		printf("%d %d\n" ,a[i].id ,a[i].c ) ;
	}
	
	return 0 ;
}

P1072 [NOIP2009 提高组] Hankson 的趣味题
暴力查就行 理论上会 t 但是好像数据比较水就暴力草过了
code:

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

int gcd(int a,int b) {
	if (a < b) swap(a, b);
	return b == 0 ? a : gcd(b, a % b);
}

int lcm(int a, int b) {
	return a / gcd(a, b) * b;
}

int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		int a0, a1, b0, b1;
		int ans = 0;
		scanf("%d%d%d%d", &a0, &a1, &b0, &b1);
		for (int i = 1; i * i <= b1; ++i) {
			if (b1 % i == 0) {
				int p = b1 / i;
				if (i % a1 == 0 && gcd(i, a0) == a1 && lcm(i, b0) == b1) ++ans;
				if (p == i) continue;
				if (p % a1 == 0 && gcd(p, a0) == a1 && lcm(p, b0) == b1) ++ans;
			}
		}
		printf("%d\n",ans);
	}
	
	return 0;
}

P1082 [NOIP2012 提高组] 同余方程
直接扩欧求解 解唯一 但是要注意负数取模问题
具体可以详见扩展欧几里得算法学习笔记
code:

#include <bits/stdc++.h>
#define ll long long
using namespace std;

void exgcd(ll a, ll b, ll &x, ll &y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return;
	}
	exgcd(b, a % b, x, y);
	ll z = x;
	x = y;
	y = z - (a / b) * y;
}

int main() {
	ll a, b, x, y;
	scanf("%lld%lld", &a, &b);
	exgcd(a, b, x, y);
	x = (x + b) % b;
	printf("%lld",x);
	
	return 0;
}

P1253 扶苏的问题
线段树 但是要考虑一下两个 tag 的下传问题
我们发现当修改标记为空时 下传区间加标记
但如果不为空 那么子树中所有的区间加标记都作废
code:

#include <bits/stdc++.h>
#define int long long
#define ls (k << 1)
#define rs (k << 1 | 1)
#define mid ((l + r) >> 1)
using namespace std;

const int N = 5e6 + 0721;
int tr[N], a[N];
int pls[N], turn[N];
int n, q;

inline void pushup(int k) {
	tr[k] = max(tr[ls], tr[rs]);
}

void build(int k, int l, int r) {
	turn[k] = -1;
	if (l == r) {
		tr[k] = a[l];
		return;
	}
	build(ls, l, mid);
	build(rs, mid + 1, r);
	pushup(k);
//	cout << k << " " << tr[k] << endl;
}

void pushdown(int k) {
	if (turn[k] != -1) {
		turn[ls] = turn[rs] = turn[k];
		pls[ls] = pls[rs] = pls[k];
		tr[ls] = tr[rs] = turn[k] + pls[k]; 
		pls[k] = 0;
		turn[k] = -1;
	} else {
		tr[rs] += pls[k];
		tr[ls] += pls[k];
		pls[ls] += pls[k];
		pls[rs] += pls[k];
		pls[k] = 0;
	}
}

void modify1(int k, int l, int r, int s, int e, int x) {
	if (l >= s && r <= e) {
		tr[k] = x;
		turn[k] = x;
		pls[k] = 0;
		return;
	}
	pushdown(k);
	if (s <= mid) modify1(ls, l, mid, s, e, x);
	if (e > mid) modify1(rs, mid + 1, r, s, e, x);
	pushup(k);
}

void modify2(int k, int l, int r, int s, int e, int x) {
	if (l >= s && r <= e) {
		tr[k] += x;
		pls[k] += x;
		return;
	}
	pushdown(k);
	if (s <= mid) modify2(ls, l, mid, s, e, x);
	if (e > mid) modify2(rs, mid + 1, r, s, e, x);
	pushup(k);
}

int query(int k, int l, int r, int s, int e) {
	if (l >= s && r <= e) {
		return tr[k];
	}
	pushdown(k);
	int res = -0x7ffffffffffffff;
	if (s <= mid) res = max(res, query(ls, l, mid, s, e));
	if (e > mid) res = max(res, query(rs, mid + 1, r, s, e));
	pushup(k);
	return res;
}

signed main() {
	ios::sync_with_stdio(false);
	
	cin >> n >> q;
	for (int i = 1; i <= n; ++i) cin >> a[i];
	build(1, 1, n);
	
	
	while (q--) {
		int opt, l, r, x;
		cin >> opt;
		if (opt == 1) {
			cin >> l >> r >> x;
			modify1(1, 1, n, l, r, x);
		} else if (opt == 2) {
			cin >> l >> r >> x;
			modify2(1, 1, n, l, r, x);
		} else {
			cin >> l >> r;
//			cout<<l<<" "<<r<<endl;
//			cout<<n<<" "<<l<<" "<<r<<endl;
			cout << query(1, 1, n, l, r) << '\n';
		}
	}
		
	return 0;
}

P1260 工程规划
纯查分约束板子 具体可以详见差分约束学习笔记
code:

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

const int N = 1e5 + 0721;
int head[N], nxt[N], to[N], len[N], cnt;
int dis[N], vis[N];
bool exist[N];
int n, m;
queue<int>q;

inline void cmb(int x, int y, int z) {
	to[++cnt] = y;
	len[cnt] = z;
	nxt[cnt] = head[x];
	head[x] = cnt;
}

bool spfa(int s) {
	memset(dis, 0x3f, sizeof dis );
	dis[s] = 0;
	q.push(s);
	exist[s] = 1;
	while (!q.empty()) {
		int now = q.front();
		q.pop();
		for (int i = head[now]; i; i = nxt[i]) {
			int y = to[i];
			if (dis[y] > dis[now] + len[i]) {
				dis[y] = dis[now] + len[i];
				if (!exist[y]) {
					q.push(y);
					exist[y] = 1;
				}
				vis[y] = vis[now] + 1;
				if (vis[y] >= n) return 1;
			}
		}
		exist[now] = 0;
	}
	return 0;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; ++i) {
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		cmb(y, x, z);
	}
	for (int i = 1; i <= n; ++i) cmb(0, i, 0);
	
	if (spfa(0))
		printf("NO SOLUTION");
	else {
		int minn = 0x7fffffff;
		for (int i = 1; i <= n; ++i) minn = min(minn, dis[i]);
		for (int i = 1; i <= n; ++i) printf("%d\n",dis[i] - minn);
	}
	
	return 0;
}

P1196 [NOI2002] 银河英雄传说
带权并查集板子 常看常新
code:

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

const int N = 30721 ;
int fa[N] , cnt[N] , tot[N] ;
int n ;

int find( int x ){
	if( x == fa[x] )
	return x ;
	int fx = find(fa[x]) ;
	cnt[x] += cnt[fa[x]] ;
	return fa[x] = fx ;
}

int main () {
	
	scanf("%d" ,&n ) ;
	for( int i = 1 ; i <= 30000 ; ++i )
	fa[i] = i , tot[i] = 1 ;
	while( n-- ){
		char c ;
		int x , y ;
		cin>>c ;
		scanf("%d%d" ,&x ,&y ) ;
		if( c == 'M' ){
			int fx = find(x) , fy = find(y) ;
			cnt[fx] += tot[fy] ;
			fa[fx] = fy ;
			tot[fy] += tot[fx] , tot[fx] = 0 ;
		}
		else{
			int fx = find(x) , fy = find(y) ;
			if( fx != fy )
			printf("-1\n") ;
			else
			printf("%d\n" ,abs( cnt[x] - cnt[y] ) - 1 ) ; 
		}
	}
	
	return 0 ;
}
posted @ 2023-06-13 20:06  Steven24  阅读(17)  评论(0)    收藏  举报