A - 神秘的老者
思路:
输
出
m
i
n
(
n
∗
a
,
b
)
即
可
输出min(n* a,b)即可
输出min(n∗a,b)即可
时间复杂度:
O
1
O1
O1
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,a,b;
cin>>n>>a>>b;
cout<<min(n*a,b)<<endl;
}
B - 借钱
思路:
暴
力
枚
举
即
可
暴力枚举即可
暴力枚举即可
判
断
一
个
浮
点
数
d
是
否
是
整
数
判断一个浮点数d是否是整数
判断一个浮点数d是否是整数
f
a
b
s
(
d
−
(
i
n
t
)
d
)
<
=
1
e
−
8
fabs(d-(int)d)<=1e-8
fabs(d−(int)d)<=1e−8
时间复杂度:
O
n
2
∗
d
On^2*d
On2∗d
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;
int n , d ;
int a[M][M] ;
double get(int a[] , int b[]) // 返回a这个点与b这个点的距离
{
double res = 0 ;
fer(i,1,d) res = res + (a[i] - b[i]) * (a[i] - b[i]) ;
return sqrt(res) ;
}
signed main()
{
cin >> n >> d ;
fer(i,1,n) fer(j,1,d) sf(a[i][j]) ;
int res = 0 ;
fer(i,1,n)
{
fer(j,i + 1 , n)
{
double d = get(a[i],a[j]) ;
if(fabs(d - (int)d) <= 1e-7)
res ++ ;
}
}
cout << res << "\n" ;
return 0;
}
C - 最小值-2019
思路:
首
先
由
取
余
的
性
质
得
首先由取余的性质得
首先由取余的性质得
(
i
∗
j
)
%
m
o
d
=
i
%
m
o
d
∗
j
%
m
o
d
(i * j)\%mod=i\%mod*j\%mod
(i∗j)%mod=i%mod∗j%mod
若
r
−
l
+
1
>
=
2019
若r - l + 1 >= 2019
若r−l+1>=2019
必
定
存
在
一
个
数
x
必定存在一个数x
必定存在一个数x
使
得
x
属
于
区
间
[
l
,
r
]
使得x属于区间[l,r]
使得x属于区间[l,r]
并
且
x
%
2019
=
0
并且x\%2019=0
并且x%2019=0
那
么
当
前
最
小
值
必
定
为
0
那么当前最小值必定为0
那么当前最小值必定为0
否
则
考
虑
暴
力
n
2
遍
历
一
遍
即
可
否则考虑暴力n^2遍历一遍即可
否则考虑暴力n2遍历一遍即可
时间复杂度:
O
n
2
On^2
On2
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;
signed main()
{
int l , r ;
cin >> l >> r ;
if((r - l + 1) >= 2019) puts("0") ;
else
{
int res = inf ;
fer(i,l,r)
{
fer(j,i + 1 , r)
{
res = min(res,i * j % 2019) ;
}
}
cout << res << "\n" ;
}
return 0;
}
D - 山 or 水库 ?
思路:
假
设
第
i
座
山
的
雨
量
为
b
[
i
]
假设第i座山的雨量为b[i]
假设第i座山的雨量为b[i]
由
题
意
可
得
由题意可得
由题意可得
a
[
1
]
=
b
[
n
]
+
b
[
1
]
2
a[1]=\frac{b[n]+b[1]}{2}
a[1]=2b[n]+b[1]
即
即
即
2
∗
a
[
1
]
=
b
[
n
]
+
b
[
1
]
2*a[1]=b[n]+b[1]
2∗a[1]=b[n]+b[1]
2
∗
a
[
2
]
=
b
[
1
]
+
b
[
2
]
2*a[2]=b[1]+b[2]
2∗a[2]=b[1]+b[2]
2
∗
a
[
3
]
=
b
[
2
]
+
b
[
3
]
2*a[3]=b[2]+b[3]
2∗a[3]=b[2]+b[3]
.
.
.
.
.
.
.
.......
.......
2
∗
a
[
n
]
=
b
[
n
−
1
]
+
b
[
n
]
2*a[n]=b[n-1]+b[n]
2∗a[n]=b[n−1]+b[n]
上
式
累
加
可
得
上式累加可得
上式累加可得
2
∗
∑
i
=
1
n
a
[
i
]
=
2
∗
∑
i
=
1
n
b
[
i
]
2*\sum_{i=1}^n a[i]=2*\sum_{i=1}^n b[i]
2∗∑i=1na[i]=2∗∑i=1nb[i]
即 ∑ i = 1 n a [ i ] = ∑ i = 1 n b [ i ] 即\sum_{i=1}^n a[i]=\sum_{i=1}^n b[i] 即∑i=1na[i]=∑i=1nb[i]
又
因
为
n
是
奇
数
又因为n是奇数
又因为n是奇数
上
述
式
子
奇
数
项
相
加
上述式子奇数项相加
上述式子奇数项相加
2
∗
a
[
1
]
+
2
∗
a
[
3
]
+
.
.
.
.
.
.
.
+
2
∗
a
[
n
]
=
b
[
1
]
+
b
[
2
]
+
b
[
3
]
+
.
.
.
.
.
.
.
.
b
[
n
]
+
b
[
n
]
2*a[1]+2*a[3]+.......+2*a[n]=b[1]+b[2]+b[3]+........b[n]+b[n]
2∗a[1]+2∗a[3]+.......+2∗a[n]=b[1]+b[2]+b[3]+........b[n]+b[n]
即 2 ∗ ∑ i = 1 2 ∗ i − 1 < = n a [ i ] = ∑ i = 1 n b [ i ] + b [ n ] 即2*\sum_{i=1}^{2*i-1<=n} a[i]=\sum_{i=1}^n b[i]+b[n] 即2∗∑i=12∗i−1<=na[i]=∑i=1nb[i]+b[n]
b [ n ] = ∑ i = 1 2 ∗ i − 1 < = n a [ i ] − ∑ i = 1 n b [ i ] = ∑ i = 1 2 ∗ i − 1 < = n a [ i ] − ∑ i = 1 n a [ i ] b[n]=\sum_{i=1}^{2*i-1<=n} a[i]-\sum_{i=1}^n b[i]=\sum_{i=1}^{2*i-1<=n} a[i]-\sum_{i=1}^n a[i] b[n]=∑i=12∗i−1<=na[i]−∑i=1nb[i]=∑i=12∗i−1<=na[i]−∑i=1na[i]
其
他
b
[
i
]
通
过
b
[
n
]
即
可
一
一
推
出
其他b[i]通过b[n]即可一一推出
其他b[i]通过b[n]即可一一推出
时间复杂度:
O
n
On
On
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;
int n ;
int a[N] ;
int b[N] ;
signed main()
{
cin >> n ;
fer(i,1,n) sf(a[i]) ;
int s1 = 0 , s2 = 0 ;
fer(i,1,n)
{
if(i & 1) s1 += 2 * a[i] ;
s2 += a[i] ;
}
b[1] = s1 - s2 ;
fer(i,1,n-1) b[i + 1] = 2 * a[i] - b[i] ;
fer(i,1,n) cout << b[i] << " " ;
return 0;
}
E - 病毒树
思路:
画
一
下
图
找
一
下
规
律
即
可
画一下图找一下规律即可
画一下图找一下规律即可
可
以
发
现
若
当
前
节
点
深
度
为
0
答
案
为
k
可以发现若当前节点深度为0答案为k
可以发现若当前节点深度为0答案为k
当
前
节
点
u
深
度
为
1
答
案
为
当前节点u深度为1答案为
当前节点u深度为1答案为
∏
i
=
1
y
=
k
−
s
y
\prod_{i=1}^{y=k-s} y
∏i=1y=k−sy
即
(
k
−
1
)
∗
(
k
−
2
)
∗
.
.
.
.
.
.
∗
(
k
−
s
)
即(k-1)*(k-2)*......*(k-s)
即(k−1)∗(k−2)∗......∗(k−s)
s
为
以
u
为
根
的
下
一
层
儿
子
数
量
s为以u为根的下一层儿子数量
s为以u为根的下一层儿子数量
当
前
节
点
u
深
度
>
=
2
答
案
为
当前节点u深度>=2答案为
当前节点u深度>=2答案为
∏
i
=
2
y
=
k
−
s
y
\prod_{i=2}^{y=k-s} y
∏i=2y=k−sy
即
(
k
−
2
)
∗
(
k
−
3
)
∗
.
.
.
.
.
.
∗
(
k
−
1
−
s
)
即(k-2)*(k-3)*......*(k-1-s)
即(k−2)∗(k−3)∗......∗(k−1−s)
s
为
以
u
为
根
的
下
一
层
儿
子
数
量
s为以u为根的下一层儿子数量
s为以u为根的下一层儿子数量
根 据 乘 法 原 理 上 述 式 子 累 乘 即 可 根据乘法原理上述式子累乘即可 根据乘法原理上述式子累乘即可
时间复杂度: O n On On
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;
int n , k ;
vector<int> g[N] ;
int ans ;
int dfs(int u , int fa , int d) // 当前节点u u的父亲节点fa u节点当前深度d
{
int tep = k - min(d,2ll) ;
for(auto j : g[u])
{
if(j == fa) continue ;
if(dfs(j,u,d + 1) == 0) return 0 ;
ans = ans * tep % mod ;
tep -- ;
}
return ans ;
}
signed main()
{
cin >> n >> k ;
int m = n - 1 ;
while(m --)
{
int a , b ;
scanf("%d %d",&a,&b) ;
g[a].pb(b) ;
g[b].pb(a) ;
}
ans = k ;
cout << dfs(1,-1,1) ;
return 0;
}
F - 多彩的树
思路:
考
虑
树
上
2
点
u
,
v
之
间
的
距
离
为
考虑树上2点u,v之间的距离为
考虑树上2点u,v之间的距离为
d
i
s
t
[
u
]
+
d
i
s
t
[
v
]
−
2
∗
d
i
s
t
[
l
c
a
(
u
,
v
)
]
dist[u] + dist[v] - 2* dist[lca(u,v)]
dist[u]+dist[v]−2∗dist[lca(u,v)]
d
i
s
t
[
i
]
为
根
节
点
到
i
节
点
的
距
离
dist[i]为根节点到i节点的距离
dist[i]为根节点到i节点的距离
l
c
a
(
u
,
v
)
为
u
,
v
节
点
的
最
近
公
共
祖
先
lca(u,v)为u,v节点的最近公共祖先
lca(u,v)为u,v节点的最近公共祖先
求
2
点
最
近
公
共
祖
先
求2点最近公共祖先
求2点最近公共祖先
对
每
个
询
问
考
虑
离
线
查
询
对每个询问考虑离线查询
对每个询问考虑离线查询
设
n
u
m
[
i
]
数
组
为
从
根
节
点
到
u
节
点
颜
色
为
i
的
边
的
数
量
设num[i]数组为从根节点到u节点颜色为i的边的数量
设num[i]数组为从根节点到u节点颜色为i的边的数量
设
s
u
m
[
i
]
数
组
为
从
根
节
点
到
u
节
点
颜
色
为
i
的
边
的
长
度
总
和
设sum[i]数组为从根节点到u节点颜色为i的边的长度总和
设sum[i]数组为从根节点到u节点颜色为i的边的长度总和
将
所
有
颜
色
值
为
c
的
边
的
长
度
改
为
d
将所有颜色值为c的边的长度改为d
将所有颜色值为c的边的长度改为d
考
虑
单
次
修
改
对
d
i
s
t
[
]
数
组
的
影
响
考虑单次修改对dist[]数组的影响
考虑单次修改对dist[]数组的影响
d
i
s
t
[
u
]
=
d
i
s
t
[
u
]
−
s
u
m
[
c
]
+
n
u
m
[
c
]
∗
d
dist[u]=dist[u]-sum[c]+num[c]*d
dist[u]=dist[u]−sum[c]+num[c]∗d
因
此
储
存
所
有
修
改
对
应
的
编
号
i
d
,
当
前
节
点
u
,
当
前
颜
色
x
,
当
前
长
度
为
y
因此储存所有修改对应的编号id,当前节点u,当前颜色x,当前长度为y
因此储存所有修改对应的编号id,当前节点u,当前颜色x,当前长度为y
d
i
s
t
[
u
]
+
d
i
s
t
[
v
]
−
2
∗
d
i
s
t
[
l
c
a
(
u
,
v
)
]
dist[u]+dist[v]−2∗dist[lca(u,v)]
dist[u]+dist[v]−2∗dist[lca(u,v)]
即
可
转
换
为
即可转换为
即可转换为
a
n
s
[
i
t
.
i
d
]
+
=
i
t
.
a
d
d
∗
(
d
i
s
t
[
u
]
−
s
u
m
[
i
t
.
x
]
+
n
u
m
[
i
t
.
x
]
∗
i
t
.
y
)
ans[it.id] += it.add * (dist[u] - sum[it.x] + num[it.x] * it.y)
ans[it.id]+=it.add∗(dist[u]−sum[it.x]+num[it.x]∗it.y)
也 可 以 树 上 莫 队 n s q r t ( n ) 或 者 树 上 建 权 值 线 段 树 n l o g n l o g n 也可以树上莫队nsqrt(n)或者树上建权值线段树nlognlogn 也可以树上莫队nsqrt(n)或者树上建权值线段树nlognlogn
方
法
1
:
l
c
a
离
线
查
询
预
处
理
方法1: lca离线查询预处理
方法1:lca离线查询预处理
时间复杂度:
O
n
l
o
g
n
Onlogn
Onlogn
#include <bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define der(i,a,b) for(re i = a ; i >= b ; -- i)
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define sf(x) scanf("%lld",&x)
#define pll pair<int,int>
#define re register int
#define int long long
#define pb push_back
#define y second
#define x first
using namespace std;
inline void sf2(int &a , int &b) { sf(a) , sf(b) ;}
const int inf = 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f ;
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ;
const double eps = 1e-7 , pi = acos(-1.0) ;
int n , m ;
int e[N] , ne[N] , h[N] , c[N] , w[N] , idx ;// 链式前向星存图的信息
int f[N][20] , d[N] ; // f d数组含义如上图
int q[N] ; // 队列数组
int ans[N] ; // 答案数组
int dist[N] ; // dist[i]为根节点到i节点的距离
int num[N] ; // 从根节点到u节点颜色为i的边的数量
int sum[N] ; // 从根节点到u节点颜色为i的边的长度总和
struct ai{
int x , y , add , id ;
};
// 颜色为x 长度为y 编号为id
// dist[u]+dist[v]−2∗dist[lca(u,v)] add为该式dist[]前面的系数
vector<ai> a[N] ;
void add(int a , int b , int cc , int dd)
{
e[idx] = b , ne[idx] = h[a] , w[idx] = dd , c[idx] = cc , h[a] = idx ++ ;
}
void bfs() // 预处理d数组和f数组
{
memset(d,0x3f,sizeof d) ;
d[0] = 0 , d[1] = 1 ;
int hh = 0 , tt = 0 ;
q[0] = 1 ;
while(hh <= tt)
{
int t = q[hh ++] ;
for(int i = h[t] ; i != -1 ; i = ne[i])
{
int j = e[i] ;
if(d[j] > d[t] + 1)
{
d[j] = d[t] + 1 ;
q[++ tt] = j ;
f[j][0] = t ;
for(int k = 1 ; k <= 16 ; k ++)
f[j][k] = f[f[j][k-1]][k-1] ;
}
}
}
}
void dfs1(int u , int fa) // 预处理dist数组
{
for(int i = h[u] ; i != -1 ; i = ne[i])
{
int j = e[i] ;
if(j == fa) continue ;
dist[j] = dist[u] + w[i] ;
dfs1(j,u) ;
}
}
int lca(int a , int b) // 返回a,b节点的最近公共祖先
{
if(d[a] < d[b]) swap(a,b) ;
for(int k = 16 ; k >= 0 ; k --)
{
if(d[f[a][k]] >= d[b])
{
a = f[a][k] ;
}
}
if(a == b) return a ;
for(int k = 16 ; k >= 0 ; k --)
{
if(f[a][k] != f[b][k])
{
a = f[a][k] ;
b = f[b][k] ;
}
}
return f[a][0] ;
}
void dfs(int u , int fa) // 离线查询预处理
{
for(auto it : a[u])
{
ans[it.id] += 1ll * it.add * (dist[u] - sum[it.x] + 1ll * num[it.x] * it.y);
}
for(int i = h[u] ; i != -1 ; i = ne[i])
{
int j = e[i] ;
if(j == fa) continue ;
num[c[i]] ++ ;
sum[c[i]] += w[i] ;
dfs(j,u) ;
num[c[i]] -- ;
sum[c[i]] -= w[i] ;
}
}
signed main()
{
int n , t ;
cin >> n >> t ;
memset(h,-1,sizeof h) ;
int m = n - 1 ;
while(m --)
{
int a , b , c , d ;
sf2(a,b) , sf2(c,d) ;
add(a,b,c,d) ;
add(b,a,c,d) ;
}
dfs1(1,-1) ;
bfs() ;
fer(i,1,t)
{
int x , y , u , v ;
sf2(x,y) , sf2(u,v) ;
int fa = lca(u,v) ;
a[u].pb({x,y,1,i}) ;
a[v].pb({x,y,1,i}) ;
a[fa].pb({x,y,-2,i}) ;
}
dfs(1,-1) ;
fer(i,1,t) cout << ans[i] << "\n" ;
return 0;
}
方 法 2 : 叶 姐 的 树 链 剖 分 + 平 衡 树 方法2: 叶姐的树链剖分+平衡树 方法2:叶姐的树链剖分+平衡树
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int getint()
{
char ch;
do{ch=getchar();}while (ch^'-'&&(ch<'0'||ch>'9'));
int ans=ch-'0';
while (isdigit(ch=getchar())) ans=ans*10+ch-'0';
return ans;
}
int rof[100001],ncnt=0;
struct T
{
int v,l,r;
long long sum,num,rnd,x;
}nod[100005];
void update(int x)
{
nod[x].num=nod[nod[x].l].num+nod[nod[x].r].num+1;
nod[x].sum=nod[nod[x].l].sum+nod[nod[x].r].sum+nod[x].x;
return ;
}
int newn(int x,int id)
{
nod[++ncnt].num=1;
nod[ncnt].sum=nod[ncnt].x=x,nod[ncnt].v=id;
nod[ncnt].rnd=rand();
return ncnt;
}
void split(int dis,int x,int &l,int &r)
{
if(!dis){l=r=0;return ;}
if(nod[dis].v<=x)
{
l=dis;
split(nod[dis].r,x,nod[dis].r,r);
}
else
{
r=dis;
split(nod[dis].l,x,l,nod[dis].l);
}
update(dis);
}
int merge(int l,int r)
{
if(l==0||r==0)
return l+r;
if(nod[l].rnd<nod[r].rnd)
{
nod[l].r=merge(nod[l].r,r);
update(l);
return l;
}
else
{
nod[r].l=merge(l,nod[r].l);
update(r);
return r;
}
}
int n,m,root;
int mod;
struct U
{
int to,nxt,c,v;
}sid[200001];
int fi[100001],cnt=0,val[100001];
void add()
{
int x,y,c,v;
x=getint();y=getint();c=getint();v=getint();
sid[++cnt].to=y;sid[cnt].nxt=fi[x];fi[x]=cnt;sid[cnt].c=c;sid[cnt].v=v;
sid[++cnt].to=x;sid[cnt].nxt=fi[y];fi[y]=cnt;sid[cnt].c=c;sid[cnt].v=v;
return ;
}
int fa[100001],siz[100001],son[100001],dep[100001],fat[100001];
void dfs1(int dis)
{
dep[dis]=dep[fa[dis]]+1;
siz[dis]=1;
for(int i=fi[dis];i;i=sid[i].nxt)
{
if(dep[sid[i].to])continue;
fa[sid[i].to]=dis;
dfs1(sid[i].to);
if(siz[dis]<siz[sid[i].to]+1)
{
siz[dis]=siz[sid[i].to]+1;
fat[dis]=sid[i].to;
}
}
return ;
}
long long V[100001];
int id[100001],top[100001],low[100001],num=0;
void dfs2(int dis,int xx)
{
if(!dis)
return ;
id[dis]=++num;
V[num]=sid[xx].v;
rof[sid[xx].c]=merge(rof[sid[xx].c],newn(sid[xx].v,num));
top[fat[dis]]=top[dis];
for(int i=fi[dis];i;i=sid[i].nxt)
if(sid[i].to==fat[dis])
dfs2(fat[dis],i);
for(int i=fi[dis];i;i=sid[i].nxt)
{
if(dis!=fa[sid[i].to]||sid[i].to==fat[dis])
continue;
top[sid[i].to]=sid[i].to;
dfs2(sid[i].to,i);
}
low[dis]=num;
return ;
}
void chg(int &x,int &y)
{
int mid;
mid=x;
x=y;
y=mid;
return ;
}
int ql,qr,lca;
bool LCA(int &x,int &y)
{
if(x==0||y==0)
return false;
if(top[x]==top[y])
{
ql=id[x];qr=id[y];
x=y=0;
if(ql>qr)
chg(ql,qr);
ql+=1;
return true;
}
if(dep[top[x]]<dep[top[y]])
chg(x,y);
if(x==top[x])
{
ql=qr=id[x];
x=fa[x];
}
else
{
ql=id[top[x]];qr=id[x];
x=fa[top[x]];
}
return true;
}
void mak()
{
dfs1(1);
top[1]=1;
dfs2(1,0);
for(int i=2;i<=n;i++)
V[i]+=V[i-1];
}
int main()
{
n=getint();m=getint();
for(int i=1;i<n;i++)
add();
mak();
for(int i(1);i<=m;i++)
{
int x,y;
long long c,v;
c=getint();v=getint();
x=getint();y=getint();
long long ans=0;
while(LCA(x,y))
{
if(ql>qr)break;
int L,mid,R;
split(rof[c],ql-1,L,mid);
split(mid,qr,mid,R);
// cout<<ql<<" "<<qr<<"\n";
ans=ans-nod[mid].sum+v*nod[mid].num-V[ql-1]+V[qr];
rof[c]=merge(merge(L,mid),R);
}
printf("%d\n",ans);
}
return 0;
}
方 法 3 : z p f 的 树 链 剖 分 + 权 值 线 段 树 方法3: zpf的树链剖分+权值线段树 方法3:zpf的树链剖分+权值线段树
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100200;
const int M=1e9+20;
struct node {
int l,r;
int colornum;
int sumpath;
}tr[N*40];
int idx=1;
int head[N];//鍙寔涔呭寲绾挎鏍戝ご鎸囬拡
int n,q;
int h[N],to[N*2],ne[N*2],idx2=1;//鍥剧殑瀛樺偍
int depth[N],f[N],sz[N],son[N],top[N],cnt;
int id[N],nw[N],nw2[N];
int w[N],w2[N];
//浠ヤ笂鏄爲閾惧墫鍒嗙殑鍙橀噺
//w琛ㄧず闀垮害锛寃2琛ㄧずcolor
int w3[N*2],w4[N*2];//杈规潈
void dfs( int rt,int fa){//灏嗚竟鏉冭浆鍖栦负鐐规潈
for( int i=h[rt];i!=-1;i=ne[i]){
int j=to[i];
if(j==fa) continue;
w2[j]=w3[i];
w[j]=w4[i];
dfs(j,rt);
}
}
void add( int a,int b,int c,int d){
w4[idx2]=d,w3[idx2]=c,to[idx2]=b,ne[idx2]=h[a],h[a]=idx2++;
}
void pushup( int rt){
tr[rt].sumpath=tr[tr[rt].l].sumpath+tr[tr[rt].r].sumpath;
tr[rt].colornum=tr[tr[rt].l].colornum+tr[tr[rt].r].colornum;
}
int create( int l,int r){
int p=idx++;
if(l==r){
tr[p].sumpath=nw[l];
return p;
}
int mid=(l+r)/2;
tr[p].l=create(l,mid);
tr[p].r=create(mid+1,r);
tr[p].sumpath=tr[tr[p].l].sumpath+tr[tr[p].r].sumpath;
return p;
}
int insert(int o,int l,int r,int val,int val_path){
int rt=idx++;
tr[rt]=tr[o];
if(l==r){
tr[rt].colornum+=1;
tr[rt].sumpath+=val_path;
return rt;
}
int mid=(l+r)/2;
if(val<=mid){
tr[rt].l=insert(tr[rt].l,l,mid,val,val_path);
}
else tr[rt].r=insert(tr[rt].r,mid+1,r,val,val_path);
pushup(rt);
return rt;
}
int q_color( int rl,int rr,int l,int r,int L,int R){
if(l>R||r<L) return 0;
if(l==r) return tr[rr].colornum-tr[rl].colornum;
if(l>=L&&r<=R) return tr[rr].colornum-tr[rl].colornum;
int mid=(l+r)/2;
int res=0;
if(mid>=L) res+=q_color(tr[rl].l,tr[rr].l,l,mid,L,R);
if(R>mid) res+=q_color(tr[rl].r,tr[rr].r,mid+1,r,L,R);
return res;
}
int q_path( int rl,int rr,int l,int r,int L,int R){
if(l>R||r<L) return 0;
if(l==r) return tr[rr].sumpath-tr[rl].sumpath;
if(l>=L&&r<=R) return tr[rr].sumpath-tr[rl].sumpath;
int mid=(l+r)/2;
int res=0;
if(mid>=L) res+=q_path(tr[rl].l,tr[rr].l,l,mid,L,R);
if(R>mid) res+=q_path(tr[rl].r,tr[rr].r,mid+1,r,L,R);
return res;
}
//浠ヤ笂鏄彲鎸佷箙鍖栫嚎娈垫爲鎿嶄綔
void dfs1( int rt,int fa){
depth[rt]=depth[fa]+1;f[rt]=fa;
sz[rt]=1;son[rt]=0;
for( int i=h[rt];i!=-1;i=ne[i]){
int j=to[i];
if(j==fa) continue;
else dfs1(j,rt);
sz[rt]+=sz[j];
if(sz[son[rt]]<sz[j])
son[rt]=j;
}
}
void dfs2( int rt,int fa){//鍏堝簭閬嶅巻dfs
id[rt]=++cnt;
nw[id[rt]]=w[rt];
nw2[id[rt]]=w2[rt];
//杩欓噷w鏄偣鏉冿紝涓嶆槸杈规潈锛宯w鏁扮粍鏄皢鏍戝睍寮€鎴愰摼寮忕粨鏋勫悗姣忎釜鐐圭殑鏉冨€?
if(son[fa]==rt) top[rt]=top[fa];
else top[rt]=rt;
if(!son[rt]) return ;
dfs2(son[rt],rt);//棣栧厛閬嶅巻閲嶅効瀛?
for( int i=h[rt];i!=-1;i=ne[i]){
int j=to[i];
if(j==fa||j==son[rt]) continue;
else dfs2(j,rt);
}
}
int query_color( int u,int v,int c){
int res=0;
while(top[u] !=top[v] ){//uv涓嶅湪鍚屼竴鏉¢摼涓?
//淇濊瘉v鍦╱鐨勪笂闈?
if(depth[top[u]]<depth[top[v]]) swap(u,v);
//鏇存柊鏍戦摼
res+=q_color(head[id[top[u]]-1],head[id[u]],1,n,c,c);
u=f[top[u]];
}
if(depth[u]<depth[v]) swap(u,v);
res+=q_color(head[id[v]],head[id[u]],1,n,c,c);
return res;
}
int query_path_val( int u,int v,int c){
int res=0;
while(top[u] !=top[v] ){//uv涓嶅湪鍚屼竴鏉¢摼涓?
//淇濊瘉v鍦╱鐨勪笂闈?
if(depth[top[u]]<depth[top[v]]) swap(u,v);
//鏇存柊鏍戦摼
res+=q_path(head[id[top[u]]-1],head[id[u]],1,n,c,c);
// cout<<id[top[u]]<<id[u]<<u<<top[u]<<endl;
u=f[top[u]];
}
if(depth[u]<depth[v]) swap(u,v);
res+=q_path(head[id[v]],head[id[u]],1,n,c,c);
return res;
}
int query_path_val_sum( int u,int v){
int res=0;
while(top[u] !=top[v] ){//uv涓嶅湪鍚屼竴鏉¢摼涓?
//淇濊瘉v鍦╱鐨勪笂闈?
if(depth[top[u]]<depth[top[v]]) swap(u,v);
res+=q_path(0,head[0],1,n,id[top[u]],id[u]);
u=f[top[u]];
}
if(depth[u]<depth[v]) swap(u,v);
res+=q_path(0,head[0],1,n,id[v]+1,id[u]);
return res;
}
int main(){
memset(h,-1,sizeof(h));
cin>>n>>q;
for( int i=1;i<n;i++){
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
add(a,b,c,d);
add(b,a,c,d);
}
dfs(1,0);
dfs1(1,0);
dfs2(1,0);
head[0]=create(1,n);
int cnt_head=1;
for( int i=2;i<=n;i++){
head[i]=insert(head[i-1],1,n,nw2[i],nw[i]);
}
for( int i=1;i<=q;i++){
int x,y,u,v;
scanf("%d%d%d%d",&x,&y,&u,&v);
int res=query_path_val_sum(u,v)-query_path_val(u,v,x)+query_color(u,v,x)*y;
printf("%d\n",res);
}
return 0;
}