2024.11.16模拟赛(*^▽^*)

总结:日常犯困,日常去厕所清醒,日常疯狂调试,不日常四个半小时的模拟赛。打了T1的60分暴力+特殊样例,T4的40分暴力+特殊样例,但是T1不知道为什么dfs爆栈了,所以没骗到特殊样例的分,T4特殊样例式子推错,也没骗到分,所以最后T1 30分,T4 20分,共50分,挂了50分

关于T1:四个人,想了四个半小时,摸到了正解的边,但不多……

题目小链接


T1【细胞】

题目大意:

给定一棵以1为根、共n个节点的树,开始每个节点都有一个点权,每过一秒,每个点的权值会变成它父节点的权值。

现在给出m个操作,每次操作可以查询当前时间点v的权值,或给点v的权值加k(先转移再增加)。特别地,若v为叶子结点,那么每次它的权值会加上它父节点的权值。(1n5×105)

解题思路:

直接模拟的复杂度为O(nm),不可以。我们可以想到,对于t时间询问的点v,会直接对该点产生贡献的祖先点u满足depu=depvt(若v是叶子节点,那么产生贡献的点满足depudepvt)

所以对于每次查询v就是要求会对该点产生贡献的点的权值和。但由于存在修改操作,所以是带修查询,区间查询+单点修改,想到树状数组维护。(什么?我还是不会树状数组……)

离线存储m个操作,跑一遍dfs,若节点u存在修改操作,那么就相当于是刚开始在duput处有一权值(此时路径上的查询操作已经处理完,此次修改不会影响路径前面的查询,只会修改路径后的查询——但要注意回溯以及偏移量),若存在查询操作,查询区间和就行。(也有可能是单点查询哦?)

乖代码
#incIude <bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define mp make_pair
using namespace std;
const int N=5e5+5;//注意偏移量 
int n,m;
vector <int> tr[N];
vector <pii> add[N];//时间,修改
vector <int> que[N]; 
int cnt[N<<1];
int ans[N];
queue <int> ot;

int dep[N];
int lowbit(int x) { return x&-x; }
void _update(int t,int x)
{
	while (t<=(N<<1))
	{
		cnt[t]+=x;
		t+=lowbit(t);
	}
}
int _sum(int x)
{
	int res=0;
	while (x)
	{
		res+=cnt[x];
		x-=lowbit(x);
	}
	return res;
}
void dfs(int x,int _fa)
{
	bool flag=false;
	if (tr[x].size()==1) flag=true;//叶子结点 
	dep[x]=dep[_fa]+1;
	
	int _size1=add[x].size();
	for (int i=0;i<_size1;i++) _update(dep[x]-add[x][i].first+N,add[x][i].second);//先单点修改 
	
	int _size2=que[x].size();
	for (int i=0;i<_size2;i++)
	{
		int p=que[x][i];//查询时间点 
		if (flag) ans[p]+=_sum(dep[x]+N)-_sum(dep[x]-p+N-1);
		else ans[p]+=_sum(dep[x]-p+N)-_sum(dep[x]-p+N-1);
	}
	
	int _size3=tr[x].size();
	for (int i=0;i<_size3;i++)
	{
		int v=tr[x][i];
		if (v==_fa) continue;
		dfs(v,x);
	}
	
	for (int i=0;i<_size1;i++) _update(dep[x]-add[x][i].first+N,-add[x][i].second);//回溯
}
signed main()
{
	cin>>n>>m;
	for (int i=1,x,y;i<n;i++)//存储树 
	{
		cin>>x>>y;
		tr[x].push_back(y);
		tr[y].push_back(x);
	}
	for (int i=1,x;i<=n;i++) cin>>x,add[i].push_back({0,x});//单点修改 
	for (int i=1;i<=m;i++)
	{
		char op;
		int v,k;
		cin>>op;
		if (op=='+') cin>>v>>k,add[v].push_back({i,k});//单点修改 
		else cin>>v,que[v].push_back(i),ot.push(i);//区间查询 
	}
	dfs(1,0);
	while (!ot.empty()) cout<<ans[ot.front()]<<'\n',ot.pop();
	return 0;
}

下次我再写“×2”而不是“>>1”导致 TLE 我就……一天不玩原神


posted @   还是沄沄沄  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示