[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 rec{int 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++

原文地址:https://www.cnblogs.com/wzc521/p/11619378.html

时间: 2024-11-06 07:14:47

[CSP-S模拟测试]:Equation(数学+树状数组)的相关文章

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

又死了......T1 Merchant 因为每个集合都可以写成一次函数的形式,所以假设是单调升的函数,那么随着t越大就越佳 而单调减的函数,随着t的增大结果越小,所以不是单调的??? 但是我们的单调只需凭借t时刻的sum值是否大于S即可 如果某个单减的集合符合情况,那么他在t==0时就符合情况 如果不符合,那么他就不会作出贡献 所以可以二分 T2 Equation 一开始以为是高斯消元??? 当然不是..... 把每个xi均用x1表示,那么我们发现,对于深度奇偶不同的点,他的表示方式是不同的,

[CSP-S模拟测试]:天才绅士少女助手克里斯蒂娜(数学+树状数组)

题目描述 红莉栖想要弄清楚楼下天王寺大叔的显像管电视对“电话微波炉(暂定)”的影响. 选取显像管的任意一个平面,一开始平面内有个$n$电子,初始速度分别为$v_i$,定义飘升系数为$$\sum \limits_{1\leqslant i<j\leqslant n}|v_i\times v_j|^2$$ 由于电视会遭到大叔不同程度的暴击,电子的速度常常会发生变化.也就是说,有两种类型的操作: $\bullet 1\ p\ x\ y$将$v_p$改为$(x,y)$ $\bullet 2\ l\ r$

【XSY2714】大佬的难题 数学 树状数组

题目描述 给你三个排列\(A,B,C\),求 \[ \sum_{1\leq x,y\leq n}[a_x<a_y][b_x<b_y][c_x<c_y] \] \(n\leq 2\times {10}^6\) 题解 就是一个三位偏序.用CDQ分治可以做到\(O(n\log^2 n)\).常熟小一点可以卡过.我在UOJ上面能跑过去. 这道题只有一个特殊性质:\(A,B,C\)都是排列. 我们记 \[ \begin{align} K_{x,y}&=[a_x<a_y]+[b_x&l

4.4 省选模拟赛 拉格朗日计数 树状数组+容斥.

像这种计数 问题什么的 是最讨厌的了... 考虑是环往环后面再续一段 暴力枚举前两个数字 树状数组统计第三个数的个数 n^2log. 考虑只枚举第个数 发现由于边界问题什么的很难处理. 再将枚举直接放到环上 发现边界问题没有了 不过存在 枚举第二个数之后 有 123 231 312 这三种形式. 第一种形式很好统计 预处理一下左边有多少个数字比自己小即可. 考虑第二种和第三种形式 很难在枚举2的时候统计出来这两种形式 考虑容斥 231=XX1-321. 312=3XX-321. 发现XX1和3X

[CSP-S模拟测试]:小P的单调数列(树状数组+DP)

题目描述 小$P$最近喜欢上了单调数列,他觉得单调的数列具有非常多优美的性质.经过小$P$复杂的数学推导,他计算出了一个单调增数列的艺术价值等于该数列中所有书的总和.并且以这个为基础,小$P$还可以求出任意一个数列的艺术价值,它等于将这个数列顺次划分若干个极长单调区间(相邻两个单调区间的单调性必须不相同)后,每个单调区间中元素总和的平均值.比如对于数列$3\ 7\ 9\ 2\ 4\ 5$,它将被划分为$[3\ 7\ 9]\ [2]\ [4\ 5]$,其艺术价值为$\frac{19+2+9}{3}

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

题目描述 平面上有$n$个点,第$i$个点的坐标为$X_i,Y_i$.对于其中的一个非空点集$S$,定义$f(S)$为一个最小矩形,满足:$\bullet$覆盖$S$中所有的点(在边界上也算覆盖):$\bullet$边与坐标轴平行.求所有不同的$f(S)$的面积和对$10^9+7$取模的结果.两个矩形被认为是不同的,当且仅当它们顶点坐标不同. 输入格式 从文件$rectangle.in$中读入数据.第一行一个整数$n$.接下来$n$行,每行两个整数$X_i,Y_i$. 输出格式 输出到文件$re

Hdu 3887树状数组+模拟栈

题目链接 Counting Offspring Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1757    Accepted Submission(s): 582 Problem Description You are given a tree, it’s root is p, and the node is numbered fr

Codeforces 216D Spider&#39;s Web 树状数组+模拟

题目链接:http://codeforces.com/problemset/problem/216/D 题意: 对于一个梯形区域,如果梯形左边的点数!=梯形右边的点数,那么这个梯形为红色,否则为绿色, 问: 给定的蜘蛛网中有多少个红色. 2个树状数组维护2个线段.然后暴力模拟一下,因为点数很多但需要用到的线段树只有3条,所以类似滚动数组的思想优化内存. #include<stdio.h> #include<iostream> #include<string.h> #in

PAT甲题题解-1095. Cars on Campus(30)-(map+树状数组,或者模拟)

题意:给出n个车辆进出校园的记录,以及k个时间点,让你回答每个时间点校园内的车辆数,最后输出在校园内停留的总时间最长的车牌号和停留时间,如果不止一个,车牌号按字典序输出. 几个注意点: 1.如果一个车连续多次进入,只取最后一个 2.如果一个车连续多次出去,只取第一个 3.一个车可能出入校园内好几次,停留时间取总和 实际上题目就是让我们求某个时间段内的车辆总和,时间段其实就相当于一个区间,区间求和的话,很快就联想到树状数组和线段树.然而怎么将时间段和区间联系起来呢,那就存储出现在记录和询问里的所有