给一颗n个点的有点权的树,有m个询问,对于每个询问u,v,k,首先将点u到点v的最短路径上的所有点按顺序编号,u的编号为1,求树链上所有点的新编号cnt满足cnt%k==0的点的权值的最大值。n,m,k<=10^5

根据k的大小分成两部分处理。原问题可转化为 deep[i] % k = a / b 。

对于k较大的,直接暴力,按照dfs序用一个栈记录下所经过的点,对于每个询问的点不停往上爬。

对于k较小的,将询问按照k分类。对于每一种k,将所有点按照dep[i] % k分类,将每个点树链剖分后hash下来的坐标再按照dep[i] % k映射到一起,用线段树进行维护。

每次查询deep[i] % k = a 时,相当于在某个区间查询最大值。

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std; #define N 100008
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define clr(x,v) memset(x,v,sizeof(x));
#define bitcnt(x) __builtin_popcount(x)
#define rep(x,y,z) for (int x=y;x<=z;x++)
#define repd(x,y,z) for (int x=y;x>=z;x--)
const int mo = ;
const int inf = 0x3f3f3f3f;
const int INF = ;
/**************************************************************************/ int T,n,m,k,sum,block,stop,cq2,tmp,label;
int lt[N],a[N],dep[N],st[N],ans[N],size[N],son[N],rk[N],w[N],top[N],mx[N<<],cl[N],cr[N],fuck[N];;
int f[N][];
struct line{
int u,v,nt;
}eg[N*];
struct que{
int u,v,lca,k,id,flag;
};
vector <que> q1[N],q2[N];
void add(int u,int v){
eg[++sum]=(line){u,v,lt[u]};
lt[u]=sum;
}
void init(){
clr(lt,); clr(ans,);
sum=; tmp=;
}
void dfs(int u,int fa){
f[u][]=fa; dep[u]=dep[fa]+; size[u]=; son[u]=;
for (int i=lt[u];i;i=eg[i].nt){
int v=eg[i].v;
if (v==fa) continue;
dfs(v,u);
size[u]+=size[v];
if (size[v]>size[son[u]]) son[u]=v;
}
}
void dfs_2(int u,int tp){
top[u]=tp; w[u]=++tmp; rk[tmp]=u;
if (son[u]) dfs_2(son[u],tp);
for (int i=lt[u];i;i=eg[i].nt){
int v=eg[i].v;
if (v==f[u][] || v==son[u]) continue;
dfs_2(v,v);
}
}
int lca(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
int d=dep[x]-dep[y];
repd(i,,)
if (d & (<<i)) x=f[x][i];
if (x==y) return x;
repd(i,,)
if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][];
}
void work_1(int u){
st[++stop]=u;
for (int i=;i<q1[u].size();i++){
int v=q1[u][i].v,x=q1[u][i].lca,k=q1[u][i].k,id=q1[u][i].id,flag=q1[u][i].flag;
if (flag)
{
int tmp=stop-k+;
while (tmp>= && dep[st[tmp]]>=dep[x]){
ans[id]=max(ans[id],a[st[tmp]]);
tmp-=k;
}
}
else
{
int tmp=dep[x]+ k - (dep[v]-dep[x]+) % k ;
while (tmp<=stop && dep[st[tmp]]<=dep[u]){
ans[id]=max(ans[id],a[st[tmp]]);
tmp+=k;
}
}
}
for (int i=lt[u];i;i=eg[i].nt){
int v=eg[i].v;
if (v==f[u][]) continue;
work_1(v);
}
st[stop--]=;
}
int query(int L,int R,int l,int r,int rt){
if (L<=l && r<=R){
return mx[rt];
}
int m=(l+r)>>;
int res=;
if (L <= m) res=max(res,query(L,R,lson));
if (m < R) res=max(res,query(L,R,rson));
return res;
} void build(int l,int r,int rt){
mx[rt]=;
if (l==r){
mx[rt]=a[rk[fuck[l]]];
return;
}
int m=(l+r)>>;
build(lson);
build(rson);
mx[rt]=max(mx[rt<<],mx[rt<<|]);
}
int calc(int L, int R, int k) {
int l = lower_bound(fuck + cl[k], fuck + cr[k] + , L) - fuck;
int r = upper_bound(fuck + cl[k], fuck + cr[k] + , R) - fuck - ;
return l <= r ? query(l,r,,n,) : ;
}
void find(int tp,int x,int cl,int id){
while (top[x]!=top[tp]){
ans[id]=max(ans[id],calc(w[top[x]],w[x],cl));
x=f[top[x]][];
}
ans[id]=max(ans[id],calc(w[tp],w[x],cl));
} vector <int> E[N];
void work_2(int k){
rep(i,,k) E[i].clear();
rep(i,,n) E[(dep[rk[i]]) % k].push_back(i);
label=;
rep(i,,k-){
cl[i]=label+;
for (int j=;j<E[i].size();j++)
fuck[++label]=E[i][j];
cr[i]=label; }
build(,n,);
for (int i=;i<q2[k].size();i++){
int u=q2[k][i].u,v=q2[k][i].v,x=q2[k][i].lca,id=q2[k][i].id;
int tmp1=(dep[x]+(dep[u]-dep[x]+) % k) % k;
int tmp2=(dep[x]+k-(dep[u]-dep[x]+) % k) % k;
find(x,u,tmp1,id);
find(x,v,tmp2,id);
}
}
int main(){
int cas=;
scanf("%d",&T);
while (T--){
printf("Case #%d:\n",++cas );
init();
scanf("%d%d",&n,&m);
rep(i,,n) scanf("%d",&a[i]);
rep(i,,n-){
int u,v;
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
dfs(,);
dfs_2(,);
rep(j,,)
rep(i,,n)
f[i][j]=f[f[i][j-]][j-];
block=;
cq2=;
rep(i,,n) q1[i].clear();
rep(i,,n) q2[i].clear();
rep(i,,m){
int u,v,k;
scanf("%d%d%d",&u,&v,&k);
int x=lca(u,v);
if (k>block)
{
q1[u].push_back((que){u,v,x,k,i,});
q1[v].push_back((que){v,u,x,k,i,});
}
else
{
q2[k].push_back((que){u,v,x,k,i,});
}
}
work_1();
rep(i,,block) if (q2[i].size()) work_2(i);
rep(i,,m) printf("%d\n",ans[i]);
}
}

HDU5840 Problem This world need more Zhu 分块 树剖的更多相关文章

  1. BZOJ4381 : [POI2015]Odwiedziny / Luogu3591[POI2015]ODW - 分块+树剖

    Solution 在步伐$pace$比较小的时候, 我们发现用前缀和直接维护会很快 而在$pace$比较大的时候, 则暴力往上跳会最优 设$blo= \sqrt{N}$ 若$pace<=blo$ ...

  2. HDU5840 (分块+树链剖分)

    Problem This world need more Zhu 题目大意 给一颗n个点的有点权的树,有m个询问,对于每个询问u,v,k,首先将点u到点v的最短路径上的所有点按顺序编号,u的编号为1, ...

  3. 【BZOJ 3295】动态逆序对 - 分块+树状数组

    题目描述 给定一个1~n的序列,然后m次删除元素,每次删除之前询问逆序对的个数. 分析:分块+树状数组 (PS:本题的CDQ分治解法见下一篇) 首先将序列分成T块,每一块开一个树状数组,并且先把最初的 ...

  4. 2018.06.30 BZOJ4765: 普通计算姬(dfs序+分块+树状数组)

    4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MB Description "奋战三星期,造台计算机".小G响应号召,花了三小时 ...

  5. 【UOJ#435】【集训队作业2018】Simple Tree 分块+树链剖分

    题目大意: 有一棵有根树,根为 1 ,点有点权.现在有 m 次操作,操作有 3 种:1 x y w ,将 x 到 y 的路径上的点点权加上 w (其中 w=±1w=±1 ):2 x y ,询问在 x ...

  6. 【BZOJ4999】This Problem Is Too Simple!(线段树)

    [BZOJ4999]This Problem Is Too Simple!(线段树) 题面 BZOJ 题解 对于每个值,维护一棵线段树就好啦 动态开点,否则空间开不下 剩下的就是很简单的问题啦 当然了 ...

  7. 【bzoj2141】排队 分块+树状数组

    题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别, ...

  8. 【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

    题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成 ...

  9. 【分块+树状数组】codechef November Challenge 2014 .Chef and Churu

    https://www.codechef.com/problems/FNCS [题意] [思路] 把n个函数分成√n块,预处理出每块中各个点(n个)被块中函数(√n个)覆盖的次数 查询时求前缀和,对于 ...

随机推荐

  1. 学习笔记 - Git

    学习参考网址:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 Git是目前世界上 ...

  2. spring整合activeMQ遇到异常:Error creating bean with name 'connectionFactory'

    异常详情 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'connect ...

  3. 清除表单input输入框内数据

    清除表单input输入框内数据 1. $(':input','#addVoucherType') //'#addVoucherType'表单id .not(':button') .val('') .r ...

  4. linux计划crontab

    linux计划crontab 启动crontab服务 一般启动服务用  /sbin/service crond start 若是根用户的cron服务可以用 sudo service crond sta ...

  5. ElasticSearch的中文分词器ik

    一.前言   为什么要在elasticsearch中要使用ik这样的中文分词呢,那是因为es提供的分词是英文分词,对于中文的分词就做的非常不好了,因此我们需要一个中文分词器来用于搜索和使用. 二.IK ...

  6. CTF—攻防练习之HTTP—PUT上传漏洞

    主机:192.168.32.152 靶机:192.168.32.159 中间件PUT漏洞 包括apache,tomcat,IIS等中间件设置支持的HTTP方法(get,post,head,delete ...

  7. typedef interrupt void (*PINT)(void)的分析

    今天写程序时,在DSP2833x_PieVect.h看到typedef interrupt void (*PINT)(void)突然一愣,上网查了下发现在这是加了interrupt 中断关键字的函数指 ...

  8. squid的三种模式

    一.squid代理服务器概述: 概述:Squid Cache(简称为Squid)是http代理服务器软件.Squid用途广泛,可以作为缓存服务器也可以作为缓存代理服务器,代理用户向web服务器请求数据 ...

  9. 【HTTP】一、HTTP协议简介及其工作流程

      协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. (一 ...

  10. 简述Object(ActiveX)控件遮挡Dialog、select下拉框的解决办法

    1.背景 最近在做项目的过程中,我们使用了Object控件,但是同时在上面写了一个select下拉框,因此每次点击下拉框的时候我们会发现,下拉框的部分内容被Object控件给遮挡了,调查研究后发现,我 ...