【牛客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 ...
随机推荐
- bzoj1011题解
[解题思路] 这题解法很多,我也不知道标算是什么..这简直就是大放水啊.. 网上流传的乱搞法,对于小范围内(假设为[1,l]∩N)暴力,大范围内估算. 我写这题时还是写P的?!..但是我看不懂我当时写 ...
- Delphi 2010下使用sqlitesimpledelphi连接SQLite数据库及中文乱码问题的解决
应女朋友的要求,要写一款销售管理的软件.用于管理服装店每天的销售记录,已及管理服装店的客户,并对客户进行生日提醒 因为之前使用C#写过一款家庭管理软件,主要是自己用,所以使用了服务器型数据库MySQL ...
- shell设置时间递减脚本
经常要用shell来做时间的定时任务,尤其是用sqoop脚本拉取数据的时候,那么假如当你要导入数据是残缺的时候呢,我写了一个能自定义时间并逐条递减的程序 #!/bin/bash . /etc/pr ...
- linux 平台安装JDK环境
1.检查一下系统中的jdk版本 [root@localhost software]# java -version 2.检测jdk安装包 [root@localhost software]# rpm - ...
- 利用Python,方便局域网内上传下载文件
因为一直在用windows系统,最近需要用到linux的服务器,两个电脑之间总是需要来回拷贝文件 这样使得很繁琐,之前一直在用Python,开启一个简单的服务器,可以在另外一台同一局域网下的电脑,在线 ...
- 通过Matlab SDK 获取tushare数据
概要说明 版本要求:Matlab需要2016b及以上版本 接口说明:可以用help pro_api和help pro_bar查看 demo程序:请参考tushare_pro_test.m文件 程序包下 ...
- IDEA与Tomcat的相关配置说明
1.IDEA会为每个Tomcat部署的项目单独建立一份配置文件 查看控制台的log输出:Using CATAINA_BASE 2.工作空间项目和Tomcat部署的web项目 WEB-INF:内的资源不 ...
- Qt学习笔记----基础知识
一.qt的本质 qt的本质是c++的图形界面类库,本身是mvc结构.qt能火最大程度 归功于它跨平台的特性,一次编码,多次编译应用. 注意:qt由于历史原因,经历了奇趣.诺基亚.digit公司,导致q ...
- vim 命令行模式 操作指令
复制n行: nyy 粘贴:p 剪切(删除)n行: ndd 剪切 ( 删除 ) n个字符:nx 移动光标到第一行 : gg 移动光标到最后一行 : G 设置格式 :gg=G 返回上一次操作前(撤销 ...
- JS函数 有参数的函数 参数可以多个,根据需要增减参数个数。参数之间用(逗号,)隔开
有参数的函数 上节中add2()函数不能实现任意指定两数相加.其实,定义函数还可以如下格式: function 函数名(参数1,参数2) { 函数代码 } 注意:参数可以多个,根据需要增减参数个数.参 ...