【牛客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 ...
随机推荐
- 使用Git 上传文件到云端(版本库)
第一步:本地初始化Git版本库 git init 第二步:链接码云(云端) git remote add orgin "你的远程仓库地址"(复制链接后结尾是.git,如果没有记得加 ...
- thinkphp 入口绑定
入口绑定是指在应用的入口文件中绑定某个模块,甚至还可以绑定某个控制器和操作,用来简化URL地址的访问. 绑定模块 例如,我们定义了一个入口文件admin.php,希望可以直接访问Admin模块,那么我 ...
- NX二次开发-UFUN初始化UF_initialize
在调用UFUN函数时必须加Uf.h头文件,代码开头和结尾加UF_initialize和UF_terminate NX9+VS2012 #include <uf.h> #include &l ...
- NX二次开发-创建一个3 x 3矩阵UF_CSYS_create_matrix
1 NX9+VS2012 #include <uf.h> #include <uf_csys.h> #include <uf_mtx.h> UF_initializ ...
- 尚学python课程---15、python进阶语法
尚学python课程---15.python进阶语法 一.总结 一句话总结: python使用东西要引入库,比如 json 1.python如何创建类? class ClassName: :以冒号结尾 ...
- gnome/KDE安装,gnome出现问题,重新安装nvdia驱动, Linux(CentOS7) NVIDIA GeForece GTX 745 显卡驱动
新安装显示gtx745驱动NVIDIA-Linux-x86_64-346.59.run, yum groupremove kde-desktop yum groupinstall "Desk ...
- Contos7 FTP 安装步骤
1. 使用rpm -q vsftpd查看是否已安装2.如未安装使用yum -y install vsftpd安装3.修改ftp配置文件vim /etc/vsftpd/vsftpd.conf,修改内容如 ...
- 3.RabbitMQ 第一个程序
RabbitMQ消息服务器主要解决应用程序之间异步消息传输问题,传统的MQ分为点对点和主题与订阅,RabbitMQ使用Exchange(交换机)实现更加灵活的消息传递. 前面介绍过几个概念,Routi ...
- hadoop2.x需要知道的默认yarn配置
在Hadoop 2.2.0中,YARN框架有很多默认的参数值,如果你是在机器资源比较不足的情况下,需要修改这些默认值,来满足一些任务需要.NodeManager和ResourceManager都是在y ...
- 《转》python 10 集合
自 http://www.cnblogs.com/BeginMan/p/3160565.html 一.目录 1.集合概述 2.关于集合的操作符.关系符号 3.集合的一系列操作(添加.更新.访问.删除) ...