首先考虑怎么暴力。

考虑把每个数进行 \(B\) 进制分解,然后我们惊奇的发现这两个操作就是把最低位去掉和往最低位后面插入一个数。

然后我们顺藤摸瓜,把每个数的分解扔到 Trie 树上,我们发现我们要找到一个节点,使得所有单词节点到其的距离之和最短,答案就是这个最短距离。

这里直接考虑一个 Trie 树上 dp,记所有单词节点到节点 \(i\) 的最短距离为 \(dp_i\),然后直接去转移。

然后考虑找找性质。

记 \(sz_i\) 表示以节点 \(i\) 为根的子树内单词节点数量,我们发现节点 \(i\) 的转移如下 \(dp_i = dp_{fa_i} - sz_j + (sz_1 - sz_j)\)。

又因为 \(sz_i \leq sz_{fa_i}\),所以只有当节点 \(i\) 满足 \(sz_i \times 2 > sz_1\) 进入到以 \(i\) 为根的子树转移才最优。

而我们又发现对于一个节点满足条件的子节点至多只有 \(1\) 个

也就是说如果把最优答案在树上的转移画出来,并称其为最优路径,那么首先这一定是一条从根出发的路径,而且以这条路径所代表的数为前缀的数一定超过总数的一半

然后有两种优化方向。

第一种是利用可持久化 Trie 树预处理,然后直接在 Trie 上利用刚刚的性质暴力 \(\log_{B} V\) 查询,缺点是对于每个 \(B\) 都要建一棵树。

第二种是因为我们只在乎最优路径上的转移,所以我们随机抽取 \(\log n\) 个节点放到 Trie 树上,显然因为这个性质类似于绝对众数的性质,因此最优的转移路径不在 Trie 上出现的可能只有 \(\frac{1}{n}\)。那么多抽取几个节点就可以基本保证一定会出现。

那么转移路径找出来了,现在问题是转移中 \(sz_i\) 怎么求?

我们有发现 \(sz_i\) 等价于 \(B\) 进制下以从根节点到节点 \(i\) 所表示的数为前缀的数的数量,而这个可以枚举这个前缀后面有几位数转变成一个连续区间上查询权值为 \([L,R]\) 的数的数量,这个可以直接主席树来搞。这么做缺点是复杂度是 \(n \log_{B}^3 V\)。

考虑到 \(\log_{2} n\) 一般远大于 \(\log_{3} n\)。

所以结合两种算法,用第一种算法解决 \(B = 2\) 的询问,用第二种算法解决其他询问。

那么就做完了。

代码极丑,慎入。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int top = 100000001;
const int maxn = 1e6+114;
struct Node{
int sz;//当前这个节点子树内有多少个单词节点
vector <pair<int,int> > edge;//边
}Trie[maxn];
struct node{
int sz;
int ls,rs;
}_01trie[maxn*30];
struct NODE{
int val;
int ls,rs;
}SGTtree[maxn*30];
int SGTroot[maxn];
int SGTtot=1;
int SGTask(int ql,int qr,int lt,int rt,int L,int R){
if(rt<ql||lt>qr){
return 0;
}
if(ql<=lt&&rt<=qr){
return SGTtree[R].val-SGTtree[L].val;
}
int mid=(lt+rt)/2;
int res=0;
res+=SGTask(ql,qr,lt,mid,SGTtree[L].ls,SGTtree[R].ls);
res+=SGTask(ql,qr,mid+1,rt,SGTtree[L].rs,SGTtree[R].rs);
return res;
}
int SGTquery(int l,int r,int cl,int cr){
return SGTask(cl,cr,1,top,SGTroot[l-1],SGTroot[r]);
}
void SGTupdate(int cur,int lst,int lt,int rt,int pos,int v){
SGTtree[cur].val=SGTtree[lst].val+v;
if(lt==rt){
return ;
}
int mid=(lt+rt)/2;
if(pos<=mid){
SGTtree[cur].rs=SGTtree[lst].rs;
SGTtree[cur].ls=++SGTtot;
SGTupdate(SGTtree[cur].ls,SGTtree[lst].ls,lt,mid,pos,v);
}
else{
SGTtree[cur].ls=SGTtree[lst].ls;
SGTtree[cur].rs=++SGTtot;
SGTupdate(SGTtree[cur].rs,SGTtree[lst].rs,mid+1,rt,pos,v);
}
}
int qpow(int a,int b){
if(b==0) return 1;
if(b==1) return min(a,top);
int res=min(qpow(a,b/2),top);
res=min(top,res*res);
if(b%2==1) res=min(res*a,top);
return min(top,res);
}
void SGTadd(int pos,int val){
SGTroot[pos]=++SGTtot;
SGTupdate(SGTroot[pos],SGTroot[pos-1],1,top,val,1);
}
int SUMQUERY(int B,int L,int R){//查询 B 进制下区间 [L,R] 所有数长度之和
int res=0;
for(int k=1;k<=30;k++){
int l=min(top,qpow(B,k-1)),r=min(top,qpow(B,k)-1);
res+=SGTquery(L,R,l,r)*k;
if(r==top) break;
}
return res;
}
int PREQUERY(int x,int B,int L,int R){//查询 B 进制下区间 [L,R] 内多少个数前缀为 x
int res=0;
for(int k=0;k<=30;k++){
int l=min(top,x*qpow(B,k)),r=min(top,(x+1)*qpow(B,k)-1);
res+=SGTquery(L,R,l,r);
if(r==top) break;
}
return res;
}
int tot=1,anser;
int _01tot=1;
int sum;
int n,m;
int flag;
stack<int> s;
int root[maxn],Sum[maxn];
void _01insert(int cur,int lst){
_01trie[cur].sz++;
s.pop();
if(s.size()==0) return ;
if(s.top()==0){
_01trie[cur].rs=_01trie[lst].rs;
_01trie[cur].ls=++_01tot;
_01trie[_01trie[cur].ls].sz+=_01trie[_01trie[lst].ls].sz;
_01insert(_01trie[cur].ls,_01trie[lst].ls);
}
else{
_01trie[cur].ls=_01trie[lst].ls;
_01trie[cur].rs=++_01tot;
_01trie[_01trie[cur].rs].sz+=_01trie[_01trie[lst].rs].sz;
_01insert(_01trie[cur].rs,_01trie[lst].rs);
}
}
void _01dfs(int l,int r,int ans,int L,int R){
if(l==0&&r==0) return ;
anser=min(anser,ans);
if(_01trie[_01trie[r].ls].sz-_01trie[_01trie[l].ls].sz>_01trie[_01trie[r].rs].sz-_01trie[_01trie[l].rs].sz){
_01dfs(_01trie[l].ls,_01trie[r].ls,ans-(_01trie[_01trie[r].ls].sz-_01trie[_01trie[l].ls].sz)+(_01trie[R].sz-_01trie[L].sz-(_01trie[_01trie[r].ls].sz-_01trie[_01trie[l].ls].sz)),L,R);
}
else{
_01dfs(_01trie[l].rs,_01trie[r].rs,ans-(_01trie[_01trie[r].rs].sz-_01trie[_01trie[l].rs].sz)+(_01trie[R].sz-_01trie[L].sz-(_01trie[_01trie[r].rs].sz-_01trie[_01trie[l].rs].sz)),L,R);
}
}
int _01query(int l,int r){
anser=INT_MAX;
_01dfs(root[l-1],root[r],Sum[r]-Sum[l-1],root[l-1],root[r]);
return anser;
}
void _01add(int x,int B,int pos){
while(x!=0){
s.push(x%B);
x/=B;
}
s.push(0);
Sum[pos]=s.size()-1+Sum[pos-1];
root[pos]=++_01tot;
_01trie[root[pos]].sz+=_01trie[root[pos-1]].sz;
_01insert(root[pos],root[pos-1]);
}
void insert(int cur,int val){
Trie[cur].sz+=val;
s.pop();
if(s.size()==0) return ;
for(pair<int,int> v:Trie[cur].edge){
if(v.second==s.top()){
insert(v.first,val);
return ;
}
}
Trie[cur].edge.push_back(make_pair(++tot,s.top()));
insert(tot,val);
}
void add(int x,int B){
while(x!=0){
s.push(x%B);
x/=B;
}
s.push(0);
sum+=s.size()-1;
insert(1,1);
}
void dfs(int cur,int ans,int PRE,int S,int B,int L,int R){
anser=min(anser,ans);
for(pair<int,int> v:Trie[cur].edge){
int nxt=PRE*B+v.second;
int g=PREQUERY(nxt,B,L,R);
if((S-g)-g>=0) continue;
dfs(v.first,ans-g+(S-g),nxt,S,B,L,R);
}
}
int query(int B,int L,int R){
anser=INT_MAX;
dfs(1,SUMQUERY(B,L,R),0,(R-L+1),B,L,R);
return anser;
}
void clear(){
for(int i=1;i<=tot;i++){
Trie[i].edge.clear();
Trie[i].sz=0;
}
sum=0;
tot=1;
}
int a[maxn];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
SGTadd(i,a[i]);
_01add(a[i],2,i);
}
while(m--){
int l,r,B;
cin>>l>>r>>B;
if(B==2){
cout<<_01query(l,r)<<"\n";
}
else{
clear();
for(int j=1;j<=22;j++){
int x=rand()%(r-l+1)+l;
add(a[x],B);
}
cout<<query(B,l,r)<<'\n';
}
}
}
/*
5 2
7 6 5 8 9
1 3 2
2 5 2
*/

P9376 题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  10. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. Linux备忘手册

    资料来源:技术胖 jspang.com 下载linux学习路径:https://newimg.jspang.com/linux-image01.png Linux备忘手册: 百度网盘 链接:https ...

  2. gorm 动态拼接查询条件

    结构体 type Mould struct { MouldId string `grom:"column:mouldID"` MouldInteriorID string `gro ...

  3. postgresql 自动类型转换

    一.错误案例 1.赋值错误: ERROR druid.sql.Statement:149 - {conn-10005, pstmt-20005} execute error. UPDATE sys_p ...

  4. Java简单实现MQ架构和思路01

    实现一个 MQ(消息队列)架构可以涉及到很多方面,包括消息的生产和消费.消息的存储和传输.消息的格式和协议等等.下面是一个简单的 MQ 架构的实现示例,仅供参考: 定义消息格式和协议:我们可以定义一个 ...

  5. .NET 采用开源软件OpenOffice 实现文档转码服务(word ppt excel)转PDF

    前言 前几年做了个项目,里面有个需求,需要在浏览器中在线浏览word excel ppt  pdf等文档. 最近又开始研究并记录下来 当时方案: 因为浏览器中阅读文档暂时只能通过pdf方式读取,所以就 ...

  6. AIRIOT训练营沈阳站圆满结束|手把手教你搞定物联网应用开发

    8月28日-9月1日,由航天科技控股集团有限公司(以下简称"航天科技")主办的<AIRIOT物联网平台应用与实战>训练营在沈阳圆满结束,来自上海电机学院.中渝软通信息技 ...

  7. Gin 框架的执行流程

    Gin框架是一个用Go语言编写的高性能Web框架,它基于httprouter实现,具有快速.简洁和高效的特性. 以下是Gin框架处理HTTP请求的大致执行流程: 1 初始化Gin引擎: 用户创建一个新 ...

  8. 【C# wpf】个人网盘练习项目总结

    采用 .net frameowrok 4.5.2 未写持久层代码,不可保存运行时的数据状态.分服务端,客户端,采用tcp通讯,使用了supersocket组件.服务端用winform ,客户端用wpf ...

  9. Vue——基本使用

    Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统.我们不再和 HTML 直接交互了.一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于这个例子是 #app ...

  10. Asp-Net-Core学习笔记:身份认证入门 _

    前言 过年前我又来更新了~ 我就说了最近不是在偷懒吧,其实这段时间还是有积累一些东西的,不过还没去整理-- 所以只能发以前没写完的一些笔记出来 就当做是温习一下啦 PS:之前说的红包封面我还没搞,得抓 ...