[2021-9-23]补题记录

20 篇文章 1 订阅
6 篇文章 0 订阅

Educational Codeforces Round 54 (Rated for Div. 2)
E. Vasya and a Tree
题目大意:给定一棵以1为根节点的树,每个节点值为0,给定若干修改,x,d,v,为x节点及其dist(x,y)<=d的子节点y,值加上v,最后输出各节点的值;解法:离线修改,使用树状数组在树上对深度进行差分,记得回溯时修改回来,避免这条子路径对另一条子路径产生影响。

#include<bits/stdc++.h>
#define pb push_back
#define se second
#define fi first
#define mp make_pair
using namespace std;
typedef long long ll;
const int N = 3e5 + 5;
#define debug(x) cout << #x <<" is " << x << endl
struct Fenwik_Tree{
	vector<ll> bit;
	int n;
	Fenwik_Tree(int _n):n(_n),bit(_n + 1,0){
	}
	void update(int pos,ll val){
		for(int i = pos;i <= n; i += i & (-i)){
			bit[i] += val; 
		}
			
	}
	ll query(int x){
		ll ans = 0;
		for(int i = x;i > 0;i -= i & (-i))
			ans += bit[i];
		return ans;
	}
};
int n,m;
vector<int> g[N];
vector<pair<ll,ll> > ask[N];
ll ans[N];

void dfs(int u,int pre,int dep,Fenwik_Tree & b){
	//cout <<u << endl;
	for(auto it : ask[u]){
		ll d = it.fi;
		ll w = it.se;
		b.update(dep,w);
		b.update(dep + d + 1,-w);
	}
	ans[u] = b.query(dep);
	for(int v : g[u])if(v != pre)dfs(v,u,dep + 1,b);
	for(auto it : ask[u]){
		ll d = it.fi;
		ll w = it.se;
		b.update(dep,-w);
		b.update(dep + d + 1,w);
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for(int i = 1;i <= n - 1;i++){
		int u,v;
		cin >> u >> v;
		g[u].pb(v);
		g[v].pb(u);
	}
	Fenwik_Tree b(n);
	
	cin >> m;
	for(int i = 1;i <= m;i++){
		ll v,d,w;
		cin >> v >> d >> w;
		ask[v].pb(mp(d,w));
	}
	dfs(1,-1,1,b);
	for(int i = 1;i <= n;i++)
		cout << ans[i] <<" \n"[i == n];
	return 0;
}

G. Array Game
题目大意:两个人交替玩游戏,选择a[i:i +m]一个大于0的值跳过去并减一,谁不能进行这样的操作谁就输了;这种题目要抓住必胜态和必败态,我们考虑ai-1后所面对的状态(因为一开始在a1就先-1了,考虑ai - 1所面对的状态比较方便),若[i + 1 ~i + m]存在必败态,那么跳过去让对手面对必败态,i为必胜态;否则当全部为必胜态时,(a[i] - 1)%2 == 1为必胜态(因为要让对手必须跳到[i + 1,i + m]并减1,让自身面对必胜态)否则为必败态;由于状态数量很少最多(1 << 5),可以用线段树优化出每个区间后接不同状态,该区间的状态;状态转移可以如下表示:`

for(int j = 0;j < all;j++){
	nodes[x].s[j] = nodes[lc(x)].s[nodes[rc(x)].s[j]];
}

考虑区间更新的情况,加偶数可以直接跳过,加奇数就是对区间进行取反,可以与处理出区间取反的结果,直接交换;

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5; 
typedef long long ll;
int n,m,q;

struct status{
	int s[1<<5];
};
ll a[N];
int all;
struct Segment_Tree{
	#define lc(x) (x<<1)
	#define rc(x) (x<<1)|1
	status nodes[N << 2][2];
	int lazy[N << 2];
	void init(int x,int t,int v){
		for(int i = 0;i < all;i++){
			if(i != all - 1 || v % 2 == 1)nodes[x][t].s[i] = (i >> 1) + (1 << (m - 1));
			else nodes[x][t].s[i] = (i >> 1);
		}
	}
	void up(int x){
		for(int i = 0;i <= 1;i++){
			for(int j = 0;j < all;j++){
				nodes[x][i].s[j] = nodes[lc(x)][i].s[nodes[rc(x)][i].s[j]];
			}
		}
	}
	void rev(int x){
		lazy[x] ^= 1;
		for(int i = 0;i < all;i++)
			swap(nodes[x][0].s[i],nodes[x][1].s[i]);
	}
	void down(int x){
		if(lazy[x] == 0)return;
		rev(lc(x));
		rev(rc(x));
		lazy[x] = 0;
	}
	void build(int x,int l,int r){
		lazy[x] = 0;
		if(l == r){
			init(x,0,(a[l] - 1) % 2);
			init(x,1,((a[l] - 1) % 2) ^ 1);
			return;
		}
		int mid = (l + r) >> 1;
		build(lc(x),l,mid);
		build(rc(x),mid + 1,r);
		up(x);
	}
	void update(int x,int cur_l,int cur_r,int l,int r){
		if(cur_l >= l && cur_r <= r){
			rev(x);
			return;
		}
		down(x);
		int mid = (cur_l + cur_r) >> 1;
		if(l <= mid)
			update(lc(x),cur_l,mid,l,r);
		if(r >= mid + 1)
			update(rc(x),mid + 1,cur_r,l,r);
		up(x);	
	}
	status query(int x,int cur_l,int cur_r,int l,int r){
		if(l <= cur_l && r >= cur_r){
			return nodes[x][0];
		}
		down(x);
		int mid = (cur_l + cur_r) >> 1;
		if(r <= mid)
			return query(lc(x),cur_l,mid,l,r);
		else if(l >= mid + 1)
			return query(rc(x),mid + 1,cur_r,l,r);
		else{
			status sl = query(lc(x),cur_l,mid,l,r);
			status sr = query(rc(x),mid + 1,cur_r,l,r);
			status ans;
			for(int i = 0;i < all;i++){
				ans.s[i] = sl.s[sr.s[i]];
			}
			return ans;
		}
	}
}seg;
int main(){
	//ios::sync_with_stdio(false);
//	cin.tie(0);
	//cout.tie(0);
	scanf("%d%d%d",&n,&m,&q);
	
	all = (1 << m);
	for(int i = 1;i <= n;i++){
		scanf("%lld",&a[i]);	
	}
	seg.build(1,1,n);
	for(int i = 1;i <= q;i++){
		int op,l,r;
		//cin >> op >> l >> r/;
		scanf("%d%d%d",&op,&l,&r);
		if(op == 1){
			ll d;
			scanf("%lld",&d);
			if(d & 1)seg.update(1,1,n,l,r);
		}else{
			status s = seg.query(1,1,n,l,r);
			if((s.s[all - 1] >> (m - 1)) & 1)
				printf("1\n");
			else
				printf("2\n");
		}
	}
	return 0;
}

Codeforces Round #521 (Div. 3)
F2. Pictures with Kittens (hard version)
题目大意:从n个数里选x个数,每相邻的k个数必须要有一个被选中,考虑dp[i][j]为选j个数且以i为结尾,那么转移方程为dp[i][j] = max(dp[i - k][j - 1] ~ dp[i - 1][j - 1]) + a[i],使用单调队列优化一下区间最大值,在这里维护单调递减,队首为最大值,维护分为三步:1、把队首超过范围的剔除,2、将尾部小于当前值的剔除(更远且更小,没用)3、将当前值加入尾部队列,优化后为n^2,(线段树n2logn超时)

#include<bits/stdc++.h>
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#define debug(x) cout<<#x<<" is "<<x<<endl
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define DBG 0
const int N = 5000 + 5;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LLINF = (1LL<<60);
using namespace std;
const int mod = 998244353;
ll fast_pow(ll a,ll b){ll ans = 1;while(b){if(b&1)ans = (ans * a)%mod;a = (a * a)%mod;b>>=1;}return (ans%mod);}
inline ll read(){ll X=0; bool flag=1; char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}if(flag) return X;return ~(X-1);}
inline void write(ll X){if(X<0) {X=~(X-1); putchar('-');}if(X>9) write(X/10);putchar(X%10+'0');}
typedef pair<int,int> pii;
typedef vector<int> vi;
inline void fastIO(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);}
inline void time_cost(clock_t start_time,clock_t end_time){cout << "The run time is: " <<(double)(end_time - start_time) / CLOCKS_PER_SEC << "s" << endl;}
inline void init(){	
	
}
ll n,k,x;
ll dp[N][N];
ll a[N];
int que[N];
int ta,he; 
inline void solve(){
	init();
	scanf("%lld%lld%lld",&n,&k,&x);
	for(int i = 1;i <= n;i++)scanf("%lld",&a[i]);
	ll ans = 0;
	if(x > n || x < n / k ){
		printf("-1\n");
		return;
	}
	for(int i = 0;i <= n;i++)
		for(int j = 0;j <= x;j++)
			dp[i][j] = -LLINF;
	dp[0][0] = 0;
	for(int j = 1;j <= x;j++){
		que[0] = 0;
		if(j == 1)ta = 1,he = 0;
		else ta = 0,he = 0;
		for(int i = 1;i <= n;i++){
		 
			while(he < ta && que[he] < i - k)he++;
			if(he < ta){
				dp[i][j] = dp[que[he]][j - 1] + a[i];
				if(j == x && n - i + 1 <= k)ans = max(ans,dp[i][j]);
			}
			while(he < ta && dp[i][j - 1] >= dp[que[ta - 1]][j - 1])ta--;
			que[ta++] = i;
		}
	}
	printf("%lld\n",ans);
	return;
} 
int main(){
	//fastIO();
#if DBG
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
#endif
	solve();

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值