首页 > 其他分享 >[CF494D] Birthday 题解

[CF494D] Birthday 题解

时间:2024-12-20 11:11:18浏览次数:7  
标签:CF494D ad int 题解 back Birthday sm push pw

首先 \(S(u)\) 显然是 \(u\) 的子树。

假如 \(u\) 是定点,问题转化为区间求平方和,十分简单。

于是我们用线段树维护区间平方和,支持区间加,然后离线问题,在 \(u\) 的位置处理即可。线段树从 \(fa\) 转移到 \(u\) 是极度简单的。

时间复杂度 \(O(n\log n)\)。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5,M=4e5+5,p=1e9+7;
int n,q,dfn[N],low[N],sm[M],pw[M],ad[M],as[N];
vector<int>g[N],w[N],qu[N],nm[N];int id,dis[N];
void push_up(int x){
	sm[x]=(sm[x*2]+sm[x*2+1])%p;
	pw[x]=(pw[x*2]+pw[x*2+1])%p;
}void down(int x,int a,int len){
	pw[x]=(pw[x]+sm[x]*a*2+len*a%p*a)%p;
	sm[x]=(sm[x]+len*a)%p,ad[x]=(ad[x]+a)%p;
}void push_down(int x,int ln,int rn){
	down(x*2+1,ad[x],rn);
	down(x*2,ad[x],ln),ad[x]=0;
}void add(int x,int l,int r,int L,int R,int v){
	if(L<=l&&r<=R)
		return down(x,v,r-l+1);
	int mid=(l+r)/2;
	push_down(x,mid-l+1,r-mid);
	if(L<=mid) add(x*2,l,mid,L,R,v);
	if(R>mid) add(x*2+1,mid+1,r,L,R,v);
	push_up(x);
}int sum(int x,int l,int r,int L,int R){
	if(L<=l&&r<=R) return pw[x];
	int mid=(l+r)/2,re=0;
	push_down(x,mid-l+1,r-mid);
	if(R>mid) re=sum(x*2+1,mid+1,r,L,R);
	if(L<=mid) re+=sum(x*2,l,mid,L,R);
	return re;
}void dfs1(int x,int fa){
	dfn[x]=++id;
	add(1,1,n,id,id,dis[x]);
	for(int i=0;i<g[x].size();i++){
		int y=g[x][i],c=w[x][i];
		if(y==fa) continue;
		dis[y]=(dis[x]+c)%p,dfs1(y,x);
	}low[x]=id;
}void dfs2(int x,int fa){
	for(int i=0;i<g[x].size();i++){
		int y=g[x][i],c=w[x][i];
		if(y==fa) continue;
		add(1,1,n,dfn[y],low[y],-c-c);
		add(1,1,n,1,n,c),dfs2(y,x);
		add(1,1,n,dfn[y],low[y],c+c);
		add(1,1,n,1,n,-c);
	}for(int i=0;i<qu[x].size();i++)
		as[nm[x][i]]=2*sum(1,1,n,dfn[qu[x][i]],low[qu[x][i]])-pw[1];
}signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		int x,y,z;cin>>x>>y>>z;
		g[x].push_back(y),g[y].push_back(x);
		w[x].push_back(z),w[y].push_back(z);
	}cin>>q,dfs1(1,0);
	for(int i=1;i<=q;i++){
		int x,y;cin>>x>>y;
		qu[x].push_back(y);
		nm[x].push_back(i);
	}dfs2(1,0);
	for(int i=1;i<=q;i++)
		cout<<(as[i]%p+p)%p<<"\n";
	return 0;
}

标签:CF494D,ad,int,题解,back,Birthday,sm,push,pw
From: https://www.cnblogs.com/chang-an-22-lyh/p/18618912/cf494d-birthday-tj

相关文章

  • Luogu P10838 『FLA - I』庭中有奇树 题解 [ 绿 ] [ 二分 ] [ 双指针 ] [ 树 ]
    庭中有奇树:很多算法揉在一起的好题。转化题意因为要封锁\(m\)条路径,根据贪心思想,他一定会封锁最短的\(m\)条路径。所以我们能走的最短传送路径就是最短的第\(m+1\)条路径。这应该是本题最关键的一步转化了,几个月前降智了根本没想到这个。做法求第\(m+1\)短的路径,这个......
  • 组合数学+ybt题解
    加法原理乘法原理排列数从\(n\)个数中任取\(m\)个元素的排列的方案数,表示为\(A^m_n=\frac{n!}{(n-m)!}\)\(0!=1\)全排列\(A^n_n\)组合数从\(n\)个元素中取出\(m\)个元素的组合的个数,表示为\(\dbinom{n}{m}=\frac{A^m_n}{m!}=\frac{n!}{m!(n-m)!}\)如何理解呢?......
  • P3316 [SDOI2014] 里面还是外面 题解
    实现有些傻瓜,喜提时空双最劣解。首先要判断一个点是否在多边形内,一个比较好的方法是从这个点向上引一条射线,若和奇数条边相交就在多边形内,否则在多边形外。二维信息,考虑用树套树维护。把多边形的每一条边都扔到它\(x\)坐标范围的线段树节点里,即线段树节点\((l,r)\)里面维护......
  • 洛谷 P11337 「COI 2019」IZLET 题解
    如果每条边连接的两个点颜色都不相同,那么可以使用如下策略确定每个点的颜色:令\(c_{i,j}\)为\(i\)到\(j\)的路径上的颜色数。对于每个点\(u\),以其为根进行一次dfs,往下找直到找到一个和它颜色相同的或者一个叶子就回溯,如果遇到颜色相同的就将它们在并查集上合并。考虑如何......
  • [Yandex Cup 2024 Qual F] Zeroth Rome 题解
    前言Englishversionofthiseditorialisprovidedafterthesamplecode.题意简述本题为交互题,你需要猜\(t\)个\([0,2024]\)间的非负整数\(x_1,x_2,\ldots,x_t\),可以询问最多\(15\)次,每次询问形如“给定一个大小为\(N(1\leN\le2025)\)的集合\(S\)满足\(S\)......
  • [APC001H] Generalized Insertion Sort 题解
    将\(a_i\)视为放在结点\(i\)上面的球;称位置\(i\)对应的球为\(i\),区别于“位置\(i\)上面的球为\(a_i\)”。考虑树是一条链的时候怎么做(下称链插入方法):此时只需要将这条链上面的球按照编号从上到下排序。这是一个类似插入排序的过程,维护深度最大的的若干个球编号的相对顺......
  • [USACO24OPEN] Grass Segments G 题解
    考虑对于一个区间\([l_i,r_i]\),最少重叠长度为\(k_i\),怎样的区间\([l_j,r_j]\)可以与前者产生贡献;首先\(r_j-l_j\gek_i\),在满足这个条件的情况下需要有\(r_j\gel_i+k_i\landl_j\ler_i-k_i\),这里\(\land\)表示合取,即C++中的\(\mathrm{and}\)。正难则反,考虑用长度\(......
  • 题解:P10483 小猫爬山
    思路第一眼我以为是个背包,但由于是分组,所以有多个缆车,明显不能用背包。我做这题是因为老师要求,那是我们在学深搜减枝,所以我就开始写深搜。这一题实际上是先选一直最重的猫,然后搞个\(sum\)数组,每搞一个新缆车的就下一个下标继续放,如果能放就放,当然也要搞一个能放但不放的。减枝......
  • RHCE环境公共问题解决(9.0)
    关于如何使用远程软件进行连接环境问题查看此处网络适配器模式,如果是NAT请修改为仅主机模式Vmware有两张网卡,一张是Vmware1,一张是Vmware8(环境必须用仅主机,避免环境判分错误)默认情况下,仅主机模式修改Vmware1网卡 打开Windows的网络适配器可以看到两张网卡 环境IP为1......
  • AT_agc030_f [AGC030F] Permutation and Minimum 题解
    先去掉相邻两个都填完的位置,对于两个都没填的记个数为\(c\),最后只需要将答案乘上\(c!\)。接下来考虑从小到大枚举所有数进行dp,记\(f_{i,j,k}\)表示考虑完前\(1\simi\),有\(j\)个数需要跟一个位置确定的数匹配,有\(k\)个数需要跟后面一个自由的数匹配,考虑当前的数:如果......