Codeforces Round #381 (Div. 2)

本文解析了ACM竞赛中的三道题目,包括树结构、线段树和区间更新等算法的应用,提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这次从D题开始写,40min写完D刚想提交就没电了,换舍友电脑安装devC又写了一遍,然后忘开longlong fst了。。。

D题:水题,对每个点二分出所能贡献的最远的那个点,预处理完后,直接无脑树剖。

晕死。。。哪需要什么树链剖分,直接利用数组维护前缀和的方法在树上dfs一下就好了。。。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n;
struct Node{
	int v,w;
};
vector<Node> G[maxn];
ll Dep[maxn];
int p[maxn];
int stk[maxn],stkn;
int u,v,w;
int dep[maxn],son[maxn],fa[maxn],siz[maxn];
int top[maxn];
int id[maxn];
int num;
int tr[maxn<<2];
int a[maxn];

void dfs1(int u,int f,int d){
	fa[u]=f;
	dep[u]=d;
	son[u]=0;
	siz[u]=1;
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i].v;
		if(v==f) continue;
		dfs1(v,u,d+1);
		if(siz[v]>siz[son[u]]) son[u]=v;
		siz[u]+=siz[v];
	}
}

void dfs2(int u,int tp){
	top[u]=tp;
	id[u]=++num;
	if(son[u]) dfs2(son[u],tp);
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i].v;
		if(v==fa[u]||v==son[u]) continue;
		dfs2(v,v);
	}
}

void build(int l,int r,int rt){
	if(l==r){
		tr[rt]=0;
		return;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
}

void update(int L,int R,int c,int l,int r,int rt){
	if(L<=l&&r<=R){
		tr[rt]+=c;
		return;
	}
	int m=(l+r)>>1;
	if(L<=m) update(L,R,c,lson);
	if(R>m) update(L,R,c,rson);
}

int query(int p,int l,int r,int rt){
	int res=0;
	res+=tr[rt];
	if(l==r) return res;
	int m=(l+r)>>1;
	if(p<=m) res+=query(p,lson);
	else res+=query(p,rson);
	return res;
}

int ask(int u){
	return query(id[u],1,n,1);
}

void change(int u,int v,int c){
   	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		update(id[top[u]],id[u],c,1,num,1);
 		u=fa[top[u]];
   	}
	if(dep[u]>dep[v]) swap(u,v);
	update(id[u],id[v],c,1,num,1);
}	   

void getDep(int u,int f,ll d){
	Dep[u]=d;
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i].v;ll w=G[u][i].w;
		if(v==f) continue;
		getDep(v,u,d+w);
	}
}

int bin(int l,int r,int u){
	int res=-1;
	while(l<=r){
		int m=(l+r)>>1;
		int v=stk[m];
		if(Dep[u]-Dep[v]<=a[u]) res=v,r=m-1;
		else l=m+1;
	}
	return res;
}

void dfs(int u,int f){
	p[u]=bin(1,stkn,u);
	stk[++stkn]=u;
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i].v;ll w=G[u][i].w;
		if(v==f) continue;
		dfs(v,u);
	}
	--stkn;
}

int main(){
	#ifndef ONLINE_JUDGE
		freopen("in.txt","r",stdin);
	#endif
	while(cin>>n){
		for(int i=1;i<=n;i++) scanf("%d",&a[i]),G[i].clear();	
		for(int u=2;u<=n;u++){
			scanf("%d%d",&v,&w);
			G[u].push_back((Node){v,w});
			G[v].push_back((Node){u,w});
			
		}
		num=0;
		dfs1(1,0,1);
		dfs2(1,1);
		build(1,num,1);
		getDep(1,0,0);
		stkn=0;
		dfs(1,0);
		for(int i=2;i<=n;i++)
			if(~p[i]) change(fa[i],p[i],1);
		for(int i=1;i<=n;i++) printf("%d ",ask(i));puts("");
	}
	return 0;
}
C题:水题。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n,m;
int l,r;

int main(){
	while(cin>>n>>m){
		int len=n+1;
		for(int i=1;i<=m;i++) scanf("%d%d",&l,&r),len=min(len,r-l+1);
		int now=0;
		cout<<len<<endl;
		for(int i=1;i<=n;i++){
			printf("%d ",now);
			now=(now+1)%len;
		}
		puts("");
	}
	return 0;
}

E题:水题。。。直接线段树维护就好了,合并的时候查询一下左右端点的值。。。一开始查询左右端点的值无脑加了个log,复杂度n*logn*logn,果断T了,然后发现只要把左右端点值放到线段树直接维护就好了,复杂度n*logn 。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n,q;
int L,R,c;
struct Node{
	ll add,lv,rv;
	int ld,rd,lu,ru;
	int Max;
};Node seg[maxn<<2];

void down(int rt){
	if(seg[rt].add){
		seg[rt<<1].add+=seg[rt].add;
		seg[rt<<1|1].add+=seg[rt].add;
		seg[rt<<1].lv+=seg[rt].add;
		seg[rt<<1|1].rv+=seg[rt].add;
		seg[rt<<1].rv+=seg[rt].add;
		seg[rt<<1|1].lv+=seg[rt].add;
		seg[rt].add=0;
	}
}

void up(int rt,int l,int r,int m){
	seg[rt].lv=seg[rt<<1].lv;
	seg[rt].rv=seg[rt<<1|1].rv;
	seg[rt].Max=max(seg[rt<<1].Max,seg[rt<<1|1].Max);
	seg[rt].ld=seg[rt<<1].ld;
	seg[rt].lu=seg[rt<<1].lu;
	seg[rt].rd=seg[rt<<1|1].rd;
	seg[rt].ru=seg[rt<<1|1].ru;
	ll a=seg[rt<<1].rv,b=seg[rt<<1|1].lv;
	if(a==b) return;
	if(a<b){
		seg[rt].Max=max(seg[rt].Max,seg[rt<<1].rd+seg[rt<<1|1].lu);
		if(seg[rt<<1].rd==m-l+1) seg[rt].lu+=seg[rt<<1|1].lu;
		if(seg[rt<<1|1].lu==r-m){
			seg[rt].ru+=seg[rt<<1].rd;
			if(seg[rt].rd==r-m) seg[rt].rd+=seg[rt<<1].rd;
		}
	}
	if(a>b){
		seg[rt].Max=max(seg[rt].Max,seg[rt<<1].ru+seg[rt<<1|1].ld);
		if(seg[rt<<1].ru==m-l+1){
			seg[rt].lu+=seg[rt<<1|1].ld;
			if(seg[rt].ld==m-l+1) seg[rt].ld+=seg[rt<<1|1].ld;
		}
		if(seg[rt<<1|1].ld==r-m) seg[rt].ru+=seg[rt<<1].ru;
	}
}

void build(int l,int r,int rt){
	seg[rt].add=0;
	if(l==r){
		scanf("%d",&c);
		seg[rt].lv=seg[rt].rv=c;
		seg[rt].ld=seg[rt].rd=seg[rt].lu=seg[rt].ru=seg[rt].Max=1;
		return;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
	up(rt,l,r,m);
}

void update(int L,int R,int c,int l,int r,int rt){
	if(L<=l&&r<=R){
		seg[rt].add+=c;
		seg[rt].lv+=c;
		seg[rt].rv+=c;
		return;
	}
	int m=(l+r)>>1;
	down(rt);
	if(L<=m) update(L,R,c,lson);
	if(R>m) update(L,R,c,rson);
	up(rt,l,r,m);
}

int main(){
	freopen("in.txt","r",stdin);
	while(~scanf("%d",&n)){
		build(1,n,1);
		scanf("%d",&q);
		while(q--){
			scanf("%d%d%d",&L,&R,&c);
			update(L,R,c,1,n,1);
			printf("%d\n",seg[1].Max);
		}
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值