[CSP-S模拟测试]:Equation(数学+树状数组)

Posted wzc521

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CSP-S模拟测试]:Equation(数学+树状数组)相关的知识,希望对你有一定的参考价值。

题目描述

有一棵$n$个点的以$1$为根的树,以及$n$个整数变量$x_i$。树上$i$的父亲是$f_i$,每条边$(i,f_i)$有一个权值$w_i$,表示一个方程$x_i+x_f_i=w_i$,这$n−1$个方程构成了一个方程组。
现在给出$q$个操作,有两种类型:
$\\bullet 1\\ u\\ v\\ s$,表示询问加上$x_u+x_v=s$这个方程后,整个方程组的解的情况。具体来说,如果方程有唯一解,输出此时$x_1$的值;如果有无限多个解,输出$inf$;如果无解,输出$none$。注意每个询问是独立的。
$\\bullet 2\\ u\\ w$,表示将$w_u$修改为$w$。


输入格式

从文件$equation.in$中读入数据。
第一行两个整数$n,q$。
接下来$n−1$行,第$i$行有两个整数$f_i+1$和$w_i+1$。
接下来$q$行,每行表示一个操作,格式见问题描述。


输出格式

输出到文件$equation.out$中。
对于每个询问输出一行表示答案。


样例

样例输入:

2 7
1 4
1 1 2 5
1 1 2 4
1 1 1 3
1 2 2 6
2 2 3
1 2 2 10
1 2 2 -10

样例输出:

none
inf
none
1
-2
8


数据范围与提示

对于所有数据,有$1\\leqslant n,q\\leqslant 10^6,1\\leqslant f_i\\leqslant i−1,1\\leqslant u,v\\leqslant n,−10^3\\leqslant w,w_i\\leqslant 10^3,−10^9\\leqslant s\\leqslant 10^9$。
$\\bullet Subtask1(3\\%)$,$n\\leqslant 10,q=0$。
$\\bullet Subtask2(18\\%)$,$n=2$。
$\\bullet Subtask3(32\\%)$,$n,q\\leqslant 10^3$。
$\\bullet Subtask4(33\\%)$,$n,q\\leqslant 10^5$。
$\\bullet Subtask5(14\\%)$,没有特殊的约束。


题解

首先,思考在没有修改的情况下如何快速求出$1$的解,其实无非就是分深度的奇偶,然后算边的前缀和罢了,比方说下图:

技术图片

不妨设$4$为已知$x$,那么$3$就是$w_3-x$,$2$就是$w_2-w_3+x$,$1$就是$w_1-w_2+w_3-x$,发现什么规律了没有?

有点类似于多步容斥的奇加偶减。

那么考虑如何修改,我们如果要改一条边,那么将会影响到这条边所连两点中儿子的整个子树,显然不能暴力修改。

发现这个问题其实就是区间修改,单点查询;不妨树状数组?

利用树状数组维护$DFS$序即可。

这个题稍卡常……

听说线段树会$TLE$?

时间复杂度:$\\Theta((n+q)\\log n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct recint nxt,to,w;e[1000001];
int head[1000001],cnt;
int n,q;
int f[1000001],w[1000001];
int sum[1000001],depth[1000001],l[1000001],r[1000001],tim;
int tr[4000001];
void add(int x,int y,int w)

	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	e[cnt].w=w;
	head[x]=cnt;

void pre_dfs(int x)

	l[x]=++tim;
	for(int i=head[x];i;i=e[i].nxt)
	
		depth[e[i].to]=depth[x]+1;
		sum[e[i].to]=w[e[i].to]-sum[x];
		pre_dfs(e[i].to);
	
	r[x]=tim;

int lowbit(int x)return x&-x;
void change(int l,int r,int w)

	for(int i=l;i<=n;i+=lowbit(i))tr[i]+=w;
	for(int i=r+1;i<=n;i+=lowbit(i))tr[i]-=w;

int ask(int x)

	int res=0;
	for(int i=l[x];i;i-=lowbit(i))res+=tr[i];
	return res*(depth[x]&1?1:-1);

int main()

	scanf("%d%d",&n,&q);
	for(int i=2;i<=n;i++)
	
		scanf("%d%d",&f[i],&w[i]);
		add(f[i],i,w[i]);
	
	depth[1]=1;
	pre_dfs(1);
	while(q--)
	
		int opt;
		scanf("%d",&opt);
		if(opt&1)
		
			int u,v,s;
			scanf("%d%d%d",&u,&v,&s);
			int flagu=sum[u]+ask(u);
			int flagv=sum[v]+ask(v);
			if((depth[u]&1)&&(depth[v]&1))
			
				long long res=1LL*s-flagu-flagv;
				if(res&1)puts("none");
				else printf("%lld\\n",res>>1);
			
			else if(!(depth[u]&1)&&!(depth[v]&1))
			
				long long res=1LL*flagu+flagv-s;
				if(res&1)puts("none");
				else printf("%lld\\n",res>>1);
			
			else
			
				if(flagu+flagv==s)puts("inf");
				else puts("none");
			
		
		else
		
			int u,v;
			scanf("%d%d",&u,&v);
			int delta=v-w[u];
			w[u]=v;
			if(!(depth[u]&1))delta=-delta;
			change(l[u],r[u],delta);
		
	
	return 0;


rp++

以上是关于[CSP-S模拟测试]:Equation(数学+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

csp-s模拟测试 56~61

[CSP-S模拟测试]:Race(数学+Trie树)

csp-s模拟测试56(10.2)Merchant「二分」·Equation「树状数组」

[CSP-S模拟测试]:小P的生成树(数学+Kruskal)

[CSP-S模拟测试]:异或(数学)

[CSP-S模拟测试]:数列(数学)