【牛客Wannafly挑战赛12】小H和圣诞树
可以考虑边分治,对于某一种颜色,我们处理出分治边左右两边所有以这个颜色为端点的路径长度,之后随便拼一拼就好了
但是这样对于每一组询问都需要边分一遍,这样做复杂度是\(O(nm+n\log n)\)的
还有一种更暴力的做法,就是枚举树上所有路径,这样就可以直接统计了,复杂度是\(O(n^2)\)的
把这两个暴力结合一下,当一个分治块大小小于\(\sqrt{n}\)的时候,我们就直接跑第二种暴力,否则我们就跑边分治
跑第二种暴力的时候我们需要快速判断当前这个点对对应哪一个询问,于是需要二分一下,于是有一个\(\log\),所以我们把阈值设得比\(\sqrt{n}\)稍小一些,使得复杂度向边分治倾斜,这样就能跑过去了
代码
#include<bits/stdc++.h>
#define re register
#define LL long long
#pragma GCC optimize(3)
#define max(a,b) ((a)>(b)?(a):(b))
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=1e5+5;const int M=4e5+3;
int rn,n,num,rt,Mnow,S,B,tot,Q,sz;
struct E{int v,nxt,w;}e[M<<1];
std::vector<int> son[M],w[M];
int vis[M],head[M],sum[M],col[maxn];
LL Ans[maxn],tax[2][maxn],b[maxn];
int st[2][M],top[2],t[2][maxn],c[maxn],qx[maxn],qy[maxn];
inline int find(LL x) {
int l=1,r=sz;
while(l<=r) {
int mid=l+r>>1;
if(b[mid]==x) return mid;
if(b[mid]<x) l=mid+1;else r=mid-1;
}
return 0;
}
inline void add(int x,int y,int w) {
e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=w;
}
void dfs1(int x,int fa) {
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa) continue;
son[x].push_back(e[i].v);w[x].push_back(e[i].w);
dfs1(e[i].v,x);
}
}
void getrt(int x,int fa) {
sum[x]=1;
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa||vis[i>>1]) continue;
getrt(e[i].v,x);sum[x]+=sum[e[i].v];
int now=max(sum[x],S-sum[x]);
if(now<Mnow) Mnow=now,rt=i;
}
}
void dfs2(int x,LL dis,int fa,int o) {
if(x<=rn) tax[o][col[x]]+=dis,st[o][++top[o]]=col[x],t[o][col[x]]++;
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa||vis[i>>1]) continue;
dfs2(e[i].v,dis+e[i].w,x,o);
}
}
void calc(int x,int fa,int o,LL dis) {
if(x<=rn&&col[x]>=o) {
int to=c[find(1ll*o*rn+col[x])];
if(to) Ans[to]+=dis;
}
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa||vis[i>>1]) continue;
calc(e[i].v,x,o,dis+e[i].w);
}
}
void dfs(int x,int fa) {
if(x<=rn) calc(x,0,col[x],0);
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa||vis[i>>1]) continue;
dfs(e[i].v,x);
}
}
void solve(int x,int s) {
if(s<=B) {dfs(x,0);return;}
Mnow=M,S=s,getrt(x,0);
if(Mnow==M) return;vis[rt>>1]=1;
dfs2(e[rt].v,e[rt].w,0,0);dfs2(e[rt^1].v,0,0,1);
for(re int i=1;i<=Q;i++) {
Ans[i]+=1ll*t[0][qx[i]]*tax[1][qy[i]]+1ll*t[1][qx[i]]*tax[0][qy[i]]
+1ll*t[0][qy[i]]*tax[1][qx[i]]+1ll*t[1][qy[i]]*tax[0][qx[i]];
}
while(top[0]) tax[0][st[0][top[0]]]=t[0][st[0][top[0]]]=0,top[0]--;
while(top[1]) tax[1][st[1][top[1]]]=t[1][st[1][top[1]]]=0,top[1]--;
int k=e[rt^1].v,h=S-sum[e[rt].v];
solve(e[rt].v,sum[e[rt].v]);solve(k,h);
}
int main() {
rn=n=read();
for(re int i=1;i<=n;i++) col[i]=read();
for(re int x,y,z,i=1;i<n;i++)
x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
dfs1(1,0);num=1;for(re int i=1;i<=n;i++) head[i]=0;int s[2];
for(re int i=1;i<=n;i++) {
int t=son[i].size();
if(t<=2) {
for(re int j=0;j<t;++j)
add(i,son[i][j],w[i][j]),add(son[i][j],i,w[i][j]);
continue;
}
s[0]=++n,s[1]=++n;
add(i,s[0],0),add(s[0],i,0);add(i,s[1],0),add(s[1],i,0);
for(re int j=0;j<t;++j)
son[s[j&1]].push_back(son[i][j]),w[s[j&1]].push_back(w[i][j]);
}
Q=read();B=0.8*std::sqrt(rn);
for(re int i=1;i<=Q;i++) {
qx[i]=read(),qy[i]=read();
if(qx[i]>qy[i]) std::swap(qx[i],qy[i]);
b[i]=1ll*qx[i]*rn+qy[i];
}
std::sort(b+1,b+Q+1);sz=std::unique(b+1,b+Q+1)-b-1;
for(re int i=Q;i;--i) c[find(1ll*qx[i]*rn+qy[i])]=i;
solve(1,n);
for(re int i=1;i<=Q;i++) {
int to=c[find(1ll*qx[i]*rn+qy[i])];
if(to!=i) {printf("%lld\n",Ans[to]);continue;}
Ans[i]/=(qx[i]==qy[i]?2ll:1);
printf("%lld\n",Ans[i]);
}
return 0;
}
【牛客Wannafly挑战赛12】小H和圣诞树的更多相关文章
- 【牛客Wannafly挑战赛12】 题解
传送门:https://www.nowcoder.com/acm/contest/79#question 说是比赛题解,其实我只会前三题: 后面的一定补 T1 题意,在一个长度为n的时间内,问如何选择 ...
- 牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树)
牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树) 链接:https://ac.nowcoder.com/acm/problem/15706 现在需要您来帮忙维护这个名册, ...
- 牛客~~wannafly挑战赛19~A 队列
链接:https://www.nowcoder.com/acm/contest/131/A来源:牛客网 题目描述 ZZT 创造了一个队列 Q.这个队列包含了 N 个元素,队列中的第 i 个元素用 Qi ...
- 牛客Wannafly挑战赛23 B.游戏
游戏 题目描述 小N和小O在玩游戏.他们面前放了n堆石子,第i堆石子一开始有ci颗石头.他们轮流从某堆石子中取石子,不能不取.最后无法操作的人就输了这个游戏.但他们觉得这样玩太无聊了,更新了一下规则. ...
- 牛客Wannafly挑战赛13-BJxc军训-费马小定理、分式取模、快速幂
参考:https://blog.csdn.net/qq_40513946/article/details/79839320 传送门:https://www.nowcoder.com/acm/conte ...
- 牛客 Wannafly 挑战赛26D 禁书目录 排列组合 概率期望
原文链接https://www.cnblogs.com/zhouzhendong/p/9781060.html 题目传送门 - NowCoder Wannafly 26D 题意 放一放这一题原先的题面 ...
- 牛客Wannafly挑战赛26E 蚂蚁开会(树链剖分+线段树)
传送门 题面描述 一颗n个节点的树,m次操作,有点权(该节点蚂蚁个数)和边权(相邻节点的距离). 三种操作: 操作1:1 i x将节点i的点权修改为x.(1 <= i <= n; 1 &l ...
- 牛客Wannafly挑战赛11E 白兔的刁难
传送门 如果大力推单位根反演就可以获得一个 \(k^2logn\) 的好方法 \[ans_{t}=\frac{1}{k}\sum_{i=0}^{k-1}(w_k^{-t})^i(w_k^i+1)^n\ ...
- 牛客Wannafly挑战赛23F 计数(循环卷积+拉格朗日插值/单位根反演)
传送门 直接的想法就是设 \(x^k\) 为边权,矩阵树定理一波后取出 \(x^{nk}\) 的系数即可 也就是求出模 \(x^k\) 意义下的循环卷积的常数项 考虑插值出最后多项式,类比 \(DFT ...
随机推荐
- Unity 中调用Android的JAVA代码
首先我们要创建一个android项目 因为项目需要使用Unity提供的接口,所以需要将接口classes.jar引入至当前工程但中.接口包的所在地,打开Finder->应用程序->Unit ...
- Go 位运算符
Go 位运算符 package main import "fmt" func main() { var a uint = 60 /* 60 = 0011 1100 */ var b ...
- css内容超出显示省略号
CSS实现单行.溢出显示省略号(…) 把要设置的显示省略号的标签,加上以下的属性 overflow: hidden; /*超出不显示*/ text-overflow: ellipsis;/* 超出内容 ...
- thinkphp 模板驱动
模板引擎驱动完成了第三方模板引擎的支持,通过定义模板引擎驱动,我们可以支持Smarty.TemplateLite.SmartTemplate和EaseTemplate等第三方模板引擎. 默认的模板引擎 ...
- PHP rand() 函数
定义和用法 rand() 函数生成随机整数. 提示:如果您想要一个介于 10 和 100 之间(包括 10 和 100)的随机整数,请使用 rand (10,100). 提示:mt_rand() 函数 ...
- 图片和base64 二进制相互转换
package com.xldz.xlworkbench.util; import java.awt.image.BufferedImage; import java.io.ByteArrayInpu ...
- 【转载】API权限设计总结
本文内容转自:http://blog.csdn.net/initphp/article/details/8636669 API权限设计总结: 最近在做API的权限设计这一块,做一次权限设计的总结. 1 ...
- ARC032 D - アットコーダーモンスターズ
https://arc032.contest.atcoder.jp/tasks/arc032_4# 切比雪夫距离,放在3000*3000的平面上, 一个集合就是恰好包含这个集合的矩形,价值是矩形长.宽 ...
- c++-文件分离
实现文件分离 1.头文件中不要使用using namespace,由于c++编译的特性,由于初学还没深入了解,不做具体编译的解释 2.由于没有了命名空间,所以string定义要写成std::strin ...
- nginx分布式实例入门操作
本文目的 前段时间学习WCF已经渐入佳境,完成了既定学习目标,转入分布式系统学习.本文技术路线是: 采用wcf实现分布式服务端和客户端,客户端部署于本地主机,nginx和WCF部署于虚拟机端(分别是三 ...