一二三系列之CodeChef分块——Chef and Churu,Chef and Problems,Children Trips

文章目录

  • Chef and Churu
    • source
    • solution
    • code
  • Chef and Problems
    • source
    • solution
    • code
  • Children Trips
    • source
    • solution
    • code

Chef and Churu

source

solution

对于单独的iii,查询可以用线段树/树状数组O(nlog⁡n)O(n\log n)O(nlogn),这暗示可以平衡查询修改次数

分块

预处理cnti,j:cnt_{i,j}:cnti,j: AjA_jAj对第iii块包含的函数贡献次数

每次修改的时候,相当于+val−Apos+val-A_{pos}+valApos

枚举块,直接整体修改cnt×(val−Apos)cnt\times(val-A_{pos})cnt×(valApos)

  • 如果是O(log⁡n)O(\log n)O(logn)修改值
  • 查询整块直接调用n\sqrt{n}n
  • 散块区间查询nlog⁡n\sqrt{n}\log nnlogn
  • 最后时间复杂度是O(Q1(n+logn)+Q2(n+nlog⁡n))O(Q_1(\sqrt{n}+logn)+Q_2(\sqrt n+\sqrt n\log n))O(Q1(n+logn)+Q2(n+nlogn))
  • 卡在查询的nlog⁡n\sqrt{n}\log nnlogn,非常难受

再分块,O(n)O(\sqrt{n})O(n) 修改,O(1)O(1)O(1)查询

tag记录整块的整体加标记,w记录散块暴力加

查询的时候,找到iii​的w值再加上所在块的整体加tag

时间复杂度O(Q1(n+n)+Q2(n+n))=O(Qn)O(Q_1(\sqrt{n}+\sqrt{n})+Q_2(\sqrt n+\sqrt n))=O(Q\sqrt n)O(Q1(n+n)+Q2(n+n))=O(Qn)

code

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define int unsigned long long
#define maxn 100005
#define maxB 320
int n, Q, B;
int A[maxn], L[maxn], R[maxn], block[maxn], sum[maxB], w[maxn], tag[maxB];
int cnt[maxB][maxn];void modify( int pos, int val ) {for( int i = 1;i <= block[n];i ++ )sum[i] += cnt[i][pos] * ( val - A[pos] );for( int i = block[pos] + 1;i <= block[n];i ++ )tag[i] += val - A[pos];for( int i = pos;i <= min( n, B * block[pos] );i ++ )w[i] += val - A[pos];A[pos] = val;
}int query( int i ) { return w[i] + tag[block[i]]; }int query( int l, int r ) {int ans = 0;if( block[l] == block[r] )for( int i = l;i <= r;i ++ )ans += query( R[i] ) - query( L[i] - 1 );else {for( int i = l;i <= B * block[l];i ++ )ans += query( R[i] ) - query( L[i] - 1 );for( int i = B * ( block[r] - 1 ) + 1;i <= r;i ++ )ans += query( R[i] ) - query( L[i] - 1 );for( int i = block[l] + 1;i < block[r];i ++ )ans += sum[i];}return ans;
}signed main() {scanf( "%llu", &n );B = sqrt( n );for( int i = 1;i <= n;i ++ ) {scanf( "%llu", &A[i] ), w[i] = A[i];block[i] = ( i - 1 ) / B + 1;}for( int i = 1;i <= n;i ++ )scanf( "%llu %llu", &L[i], &R[i] );for( int i = 1;i <= n;i ++ )w[i] += w[i - 1];for( int i = 1;i <= block[n];i ++ ) {for( int j = ( i - 1 ) * B + 1;j <= min( n, i * B );j ++ )cnt[i][L[j]] ++, cnt[i][R[j] + 1] --;for( int j = 1;j <= n;j ++ )cnt[i][j] += cnt[i][j - 1];for( int j = 1;j <= n;j ++ )sum[i] += cnt[i][j] * A[j];}scanf( "%llu", &Q );int opt, x, y;while( Q -- ) {scanf( "%llu %llu %llu", &opt, &x, &y );if( opt & 1 ) modify( x, y );else printf( "%llu\n", query( x, y ) );}return 0;
}

Chef and Problems

source

solution

分块

预处理出整块i,ji,ji,j之间的答案

具体而言,用lastilast_ilasti记录年龄为iii的第一个人的出现位置,显然越往后的人与第一个年龄相同的人距离越大

对于查询,包含的整块直接调用预处理的数组

散块部分,就在区间中lower_bound找最远的,把人按年龄分道不同容器vector找坐标

code

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define maxn 100005
#define maxB 1005
vector < int > pos[maxn];
int n, m, Q, B;
int A[maxn], block[maxn], last[maxn];
int len[maxB][maxB];int main() {scanf( "%d %d %d", &n, &m, &Q );B = 100;for( int i = 1;i <= n;i ++ ) {scanf( "%d", &A[i] );block[i] = ( i - 1 ) / B + 1;}for( int i = 1;i <= block[n];i ++ ) {for( int j = 1;j <= m;j ++ ) last[j] = 0;int l = ( i - 1 ) * B + 1, ans = 0;for( int j = l;j <= n;j ++ ) {if( ! last[A[j]] ) last[A[j]] = j;else ans = max( ans, j - last[A[j]] );if( j % B == 0 ) len[i][block[j]] = ans; }}for( int i = 1;i <= n;i ++ ) pos[A[i]].push_back( i );while( Q -- ) {int l, r;scanf( "%d %d", &l, &r );int ans = len[block[l] + 1][block[r] - 1];for( int i = l;i <= min( r, block[l] * B );i ++ ) {int p = lower_bound( pos[A[i]].begin(), pos[A[i]].end(), r ) - pos[A[i]].begin() - 1;if( ! ~ p ) continue;else ans = max( ans, pos[A[i]][p] - i );}for( int i = max( l, ( block[r] - 1 ) * B + 1 );i <= r;i ++ ) {int p = lower_bound( pos[A[i]].begin(), pos[A[i]].end(), l ) - pos[A[i]].begin();if( p == pos[A[i]].size() ) continue;else ans = max( ans, i - pos[A[i]][p] );}printf( "%d\n", ans );}return 0;
}

Children Trips

source

solution

dfs确定每个点到根的距离disdisdis以及深度depdepdep

cccn\sqrt{n}n的大小关系分块

  • c>nc>\sqrt nc>n

    对于u,vu,vu,v,找到其lcalcalca,暴力一次一次跳,一次最多跳ppp长度,最多跳n\sqrt nn

    最后得到跳的次数以及距离lcalcalca的距离,两个距离合在一起看是再跳一次还是两次

  • c≤nc\le \sqrt ncn

    这个时候就不能暴力跳了,因为可能会达到nnn级别

    但是ccc最多只有n\sqrt nn个取值

    将排序按ccc从小到大排序,预处理倍增数组gi,j:g_{i,j}:gi,j:iii2j2^j2j​次所达到的点

按理来说O(nnlog⁡n)O(n\sqrt n \log n)O(nnlogn)有点尴尬,但这道题是八秒,交上去倒是挺快的,╮(╯▽╰)╭

code

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define Pair pair < int, int >
#define maxn 100005
int n, m, B;
vector < Pair > G[maxn];
int dis[maxn], dep[maxn], ans[maxn];
int f[maxn][20], g[maxn][20];void dfs( int u, int fa ) {f[u][0] = fa, dep[u] = dep[fa] + 1;for( int i = 1;i <= 16;i ++ )f[u][i] = f[f[u][i - 1]][i - 1];for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first;int w = G[u][i].second;if( v == fa ) continue;else dis[v] = dis[u] + w, dfs( v, u );}
}struct node {int u, v, p, id;node(){}node( int U, int V, int P, int ID ) { u = U, v = V, p = P, id = ID; }
}block_little[maxn], block_large[maxn];int get_lca( int u, int v ) {if( dep[u] < dep[v] ) swap( u, v );for( int i = 16;~ i;i -- ) if( dep[f[u][i]] >= dep[v] ) u = f[u][i];if( u == v ) return u;for( int i = 16;~ i;i -- ) if( f[u][i] ^ f[v][i] ) u = f[u][i], v = f[v][i];return f[u][0];
}int jump_once( int u, int p ) {int t = u;for( int i = 16;~ i;i -- ) {if( dis[u] - dis[f[t][i]] > p ) continue;else t = f[t][i];}return t;
}Pair climb_large( int u, int lca, int p ) {int cnt = 0;while( u ^ lca ) {int t = jump_once( u, p );if( dep[t] > dep[lca] ) cnt ++, u = t;else break;}return make_pair( cnt, dis[u] - dis[lca] );
}void solve_large( int n ) {for( int i = 1;i <= n;i ++ ) {int u = block_large[i].u;int v = block_large[i].v;int p = block_large[i].p;int id = block_large[i].id;int lca = get_lca( u, v );Pair l = climb_large( u, lca, p );Pair r = climb_large( v, lca, p );int len = l.second + r.second;ans[id] = l.first + r.first + ( int )ceil( len * 1.0 / p );}
}Pair climb_little( int u, int lca, int p ) {int cnt = 0;for( int i = 16;~ i;i -- )if( dep[g[u][i]] > dep[lca] ) cnt += 1 << i, u = g[u][i];return make_pair( cnt, dis[u] - dis[lca] );
}void build( int p ) {for( int i = 1;i <= n;i ++ ) g[i][0] = jump_once( i, p );for( int j = 1;j <= 16;j ++ )for( int i = 1;i <= n;i ++ )g[i][j] = g[g[i][j - 1]][j - 1];
}void solve_little( int n ) {sort( block_little + 1, block_little + n + 1, []( node x, node y ) { return x.p < y.p; } );for( int i = 1;i <= n;i ++ ) {int u = block_little[i].u;int v = block_little[i].v;int p = block_little[i].p;int id = block_little[i].id;int lca = get_lca( u, v );if( p != block_little[i - 1].p ) build( p );Pair l = climb_little( u, lca, p );Pair r = climb_little( v, lca, p );int len = l.second + r.second;ans[id] = l.first + r.first + ( int )ceil( len * 1.0 / p );}
}int main() {scanf( "%d", &n );for( int i = 1, u, v, w;i < n;i ++ ) {scanf( "%d %d %d", &u, &v, &w );G[u].push_back( make_pair( v, w ) );G[v].push_back( make_pair( u, w ) ); }dfs( 1, 0 );B = sqrt( n );scanf( "%d", &m );int little = 0, large = 0;for( int i = 1, u, v, p;i <= m;i ++ ) {scanf( "%d %d %d", &u, &v, &p );if( p <= B ) block_little[++ little] = node( u, v, p, i );else block_large[++ large] = node( u, v, p, i );}solve_large( large );	solve_little( little );for( int i = 1;i <= m;i ++ ) printf( "%d\n", ans[i] );return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317267.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Bob‘s Problem

Bob’s Problem 题意&#xff1a; 一个有n个点的图&#xff0c;其中边分为白色和黑色&#xff0c;每个边都有边权&#xff0c;所选白边的数量的数量不能超过k&#xff0c;问现在选择一些边&#xff0c;使得所有点连通&#xff0c;问最大权值是多少&#xff1f; 题解&#xf…

.NET Core 开源项目 Anet 在路上

今天给大家介绍我刚开源的一个 .NET Core 项目&#xff1a;Anet。Anet 的目标是实现一个 .NET Core 通用库、通用框架和通用模板。我给它的定义是&#xff1a;A .NET Core Common Lib, Framework and Boilerplate.它的取名正是来自于这句话的前面四个字母&#xff1a;ANET。Ane…

Loj#2324-「清华集训 2017」小 Y 和二叉树

正题 题目链接:https://loj.ac/p/2324 题目大意 给出nnn个点的一棵树&#xff0c;每个点的度数不超过333。 你要求它的一个二叉树结构&#xff08;根任意选择&#xff09;使得其中序遍历的字典序最小。 1≤n≤1061\leq n\leq 10^61≤n≤106 解题思路 直接找根感觉比较麻烦&…

模板:后缀自动机(SAM)

所谓后缀自动机&#xff0c;就是通过后缀建立的自动机 &#xff08;逃&#xff09; 请允许我先介绍一下后缀家族&#xff1a; &#xff08;又逃&#xff09; 前言 OI生涯目前为止学习的最为难以理解的算法&#xff0c;没有之一。 到现在也没有完全的理解。 qwq 概念 定义&…

.NET 开源项目 Anet 介绍

使用 Anet 有一段时间了&#xff0c;已经在我的个人网站&#xff08;如 bookist.cc&#xff09;投入使用&#xff0c;目前没有发现什么大问题&#xff0c;所以才敢写篇文章向大家介绍。GitHub 地址&#xff1a;https://github.com/anet-team/anetAnet 是一个 .NET Core 通用框架…

线性代数问卷调查反馈——Find The Determinant III,Takahashi‘s Basics in Education and Learning

文章目录Find The Determinant IIIsourcecodeTakahashis Basics in Education and LearningsourcecodeFind The Determinant III source 高斯消元求行列式的模板题 code #include <cstdio> #include <iostream> using namespace std; #define maxn 205 #define…

L - Who is the Champion

L - Who is the Champion 计蒜客 - 42587 题意&#xff1a; 给出一个N阶矩阵&#xff0c;&#xff08; i , j &#xff09; &#xff08;i, j&#xff09;&#xff08;i,j&#xff09;处的数字表示这场比赛球队i ii踢进球队j jj多少球。两支球队平局则各加一分&#xff0c;一…

CF1037H Security(SAM)

解析 算是一个比较高级的SAM的应用了 对fail树的dfs序建立维护右端点最大值的线段树 考虑把所有的询问离线&#xff0c;按照右端点排序 每次动态把当前询问右端点左侧的前缀插入线段树 处理询问时&#xff0c;先贪心的尝试和询问串填法一样&#xff0c;如果不行就往下一个字母…

AT5147-[AGC036D]Negative Cycle【dp,模型转换】

正题 题目链接:https://www.luogu.com.cn/problem/AT5147 题目大意 有nnn个点的一张图&#xff0c;其中i→i1(i<n)i\rightarrow i1(i< n)i→i1(i<n)有一条边权值为000。 对于其他i,j(i≠j)i,j(i\neq j)i,j(ij)存在一条边i→ji\rightarrow ji→j&#xff0c;若i&l…

栈/队列/分块问卷调查反馈——Weak in the Middle,Cutting Plants,最小公倍数

文章目录Weak in the MiddlesourcesolutioncodeCutting Plantssourcesolutioncode[HNOI2016]最小公倍数sourcesolutioncodeWeak in the Middle source solution 栈模拟。 天数的计算&#xff0c;可以发现与其参与三元比较的次数有关 对于栈顶&#xff0c;如果被弹出&#…

我的十年创业路

记十年创业的心路历程和我的创业思辨导读1 为什么写这篇文章2 详细的总结和思辨 2.01 感恩 2.02 为什么创业 2.03 十年流水账 2.04 经历了哪些失败 2.05 重要的职场基础 2.06 持续的学习和进步 2.07 创业与兴趣 2.08 价值观的碰撞和选择 2.09 合作与…

C - And and Pair

C - And and Pair 题意&#xff1a; 问有多少组(i,j)满足要求。 要求为&#xff1a; 0<j<i<n i&ni i&j0 答案mod 1e97 题解&#xff1a; 这个和我的思路时一样的&#xff0c;且讲的更清楚 i&ni说明n为0的地方&#xff0c;i必须为0&#xff1b;n为1的地…

CF850F Rainbow Balls(数学、期望)

解析 二倍相邻项&#xff0c;就要想裂项 纯数学题 一道黑色的小凯的疑惑 设总球数为 sss 我们先钦定一种颜色留到最后&#xff0c;那么其他颜色可以等价考虑 设 fif_{i}fi​ 为钦定的颜色的球有 iii 个&#xff0c;涂完需要的期望次数 则有&#xff1a; fi(fi−1fi1)pfi(1−2p…

pjudge#21652-[PR #4]到底有没有九【数位dp】

正题 题目链接:http://pjudge.ac/problem/21652 题目大意 给出一个正整数kkk&#xff0c;求第nnn个xxx满足x(10k−1)x\times (10^k-1)x(10k−1)中没有一个数位为999。 1≤n≤1018,1≤k≤181\leq n\leq 10^{18},1\leq k\leq 181≤n≤1018,1≤k≤18 解题思路 首先是从高位到低…

专题突破二之优先队列、st表——,Running Median,Sequence,Buy Low Sell High,数据备份,超级钢琴,ZQC的手办

文章目录Running MedianSequenceBuy Low Sell High[APIO/CTSC 2007] 数据备份[NOI2010] 超级钢琴「LibreOJ β Round」ZQC 的手办Running Median source 对顶栈 用大根堆和小根堆一起维护 若元素小于等于大根堆栈顶&#xff0c;放入大根堆否则放入小根堆 大根堆维护的就是…

G - Eating Plan

G - Eating Plan 题意&#xff1a; 一个1到n组成的排列&#xff0c;每个数的价值为其阶乘&#xff0c;有m个询问ki&#xff0c;要求你在排列中选取连续的一块&#xff0c;使得价值和mod 998857459 后&#xff0c;大于ki&#xff0c;问最短区间长度&#xff0c;如果不存在输出…

P4770:你的名字(SAM、线段树合并)

文章目录前言解析前言 1000A快乐&#xff01;&#xff01;&#xff01;awa 没有想象中的那么恶心。 解析 先考虑每次都询问 [1,n][1,n][1,n] 如何做。 正难则反&#xff0c;用T所有本质不同串数量减去是S串子串又是T的子串的数量 前者很好求&#xff0c;关键是后者 首先可以…

DotNetty 实现 Modbus TCP 系列 (一) 报文类

Modbus TCP/IP 报文报文最大长度为 260 byte (ADU 7 byte MBAP Header 253 byte PDU)Length Unit Identifier 长度 PDU 长度MBAP HeaderPDUPDU 由两部分构成&#xff1a;Function Code(功能码) 和 Data 组成Function Code部分功能码&#xff1a;报文类ModbusHeaderModbusHe…

AT2377-[AGC014E]Blue and Red Tree【启发式合并】

正题 题目链接:https://www.luogu.com.cn/problem/AT2377 题目大意 有两棵树T1,T2T_1,T_2T1​,T2​。T1T_1T1​树上的边开始时都是蓝色的&#xff0c;我们每次选择一条蓝色边路径(x,y)(x,y)(x,y)&#xff0c;然后删掉路径上一条边&#xff0c;连接一条xxx到yyy的红色边。 要…

B - A Funny Bipartite Graph

B - A Funny Bipartite Graph 题意&#xff1a; 一个二分图&#xff0c;左右各有n个点&#xff0c;左边第i个点有一个属性mi&#xff0c;它在一个图中的价值为midi,其中di为它在图中的度数(特殊的&#xff0c;如果度数为0&#xff0c;则价值为0)&#xff0c;求一个该二分图的…