线段树

省选模拟4 题解

早过忘川 提交于 2020-01-12 13:19:18
A. 点点的圈圈 因为题中保证的特殊性质,容易发现圆之间的关系形成树形结构。 对于每棵子树,选择树的根或者累计所有子树的答案。 问题在于建图,容易发现这个可以用KDTree优化。 考虑将所有的点建在KDTree上。 用每个点的圆覆盖KDTree,当完全覆盖时直接塞入对应点的vector中。 之后DFS一遍KDTree,同时用一个set维护祖先链上所有的vector的集合。 set所表示的集合即能覆盖该点的所有的圆。 对于KDTree中每一个点,直接在set中查后继就可以找到他的父亲。 B. 点点的计算 根据大神的一番推导证明,可得原式$=lcm_{i=n-k+1}^n i$ 考虑求出一个数组$b_{i,j}$,使得$\prod_{i=n-k+1}^{n} b_{n,i}=lcm_{i=n-k+1}^n i$,即每向左一步的增量。 问题在于如何通过$b_{n-1}$推出$b_n$。 直接令$b_{n}=b_{n-1}$,$b_{n,n}=n$,然后发现前面一些贡献出错了。 对于前面的$b_{n,i}$中含有$n$的一些质因子,统计重复了,所以不断乘逆元消掉。 这个玩意可以直接用一些栈来维护。 为了在线的回答询问,将这个数组通过可持久化线段树实现就好了。 容易发现取$lcm$对应着指数取$max$。 所以这个做法实际上是对这个指数最值的差分,实际上与$zkw

P1198 [JSOI2008]最大数 线段树

China☆狼群 提交于 2020-01-12 09:17:48
   题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1、 查询操作。 语法: Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。 限制: L L不超过当前数列的长度。 (L > 0) ( L > 0 ) 2、 插入操作。 语法: A n 功能:将 n n加上 t t,其中 t t是最近一次查询操作的答案(如果还未执行过查询操作,则 t=0 t = 0),并将所得结果对一个固定的常数 D D取模,将所得答案插入到数列的末尾。 限制: n n是整数(可能为负数)并且在长整范围内。 注意:初始时数列是空的,没有一个数。 输入输出格式 输入格式: 第一行两个整数, M M和 D D,其中 M M表示操作的个数 (M \le 200,000) ( M ≤ 2 0 0 , 0 0 0 ), D D如上文中所述,满足 (0<D<2,000,000,000) ( 0 < D < 2 , 0 0 0 , 0 0 0 , 0 0 0 ) 接下来的 M M行,每行一个字符串,描述一个具体的操作。语法如上文所述。 输出格式: 对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。 输入输出样例 输入样例#1: 复制 5 100 A 96 Q 1 A 97 Q 1 Q 2 输出样例#1: 复制 96 93 96目前做过最简单的线段树了 这种题目蓝题属实不科学

[FJOI2015]火星商店问题

北城以北 提交于 2020-01-12 06:10:43
description 题面 solution 跟着各位dalao写了一下线段树分治的题 我们把修改和询问按照时间建立线段树分治, 对于每一个修改标记永久化,对于每一个区间进行区间覆盖 主要的想法就是对每一个线段树节点开一个 \(vector\) 记录所有的修改和询问 在线段树上的一条链上插入修改,使用区间覆盖的方法在线段树上插入询问 对整棵线段树进行 \(dfs\) ,每次取出节点上的 \(vector\) 并对其进行处理 大概就是这样 void segdiv(int i,int l,int r){//线段树分治??? work(f[i],g[i]);if(l==r)return;segdiv(ls,l,mid);segdiv(rs,mid+1,r); } il void insertmodify(int i,int l,int r,int x,int y,modify mdf){ //这里是插入修改 f[i].push_back(mdf); if(l==r)return; if(x<=mid)insertmodify(ls,l,mid,x,y,mdf); else insertmodify(rs,mid+1,r,x,y,mdf); } il void insertquery(int i,int l,int r,int x,int y,ask q){ //这里是插入询问 if(y

P3373 线段树乘法模板 P2023 [AHOI2009]维护序列

徘徊边缘 提交于 2020-01-12 03:19:53
   题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k 操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k 操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果 输出格式: 输出包含若干行整数,即为所有操作3的结果。 输入输出样例 输入样例#1: 复制 5 5 38 1 5 4 2 3 2 1 4 1 3 2 5 1 2 4 2 2 3 5 5 3 1 4 输出样例#1: 复制 17 2 说明 时空限制:1000ms,128M 数据规模: 对于30%的数据:N<=8,M<=10 对于70%的数据:N<=1000,M<=10000 对于100%的数据:N<=100000,M<=100000 多一个乘法标记 调的欲仙欲死 记住一个原则 先乘后加!!! #include<bits/stdc++.h> using namespace std; /

LCIS(线段树区间合并)

和自甴很熟 提交于 2020-01-12 00:17:22
LCIS Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5912 Accepted Submission(s): 2563 Problem Description Given n integers. You have two operations: U A B: replace the Ath number by B. (index counting from 0) Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b]. Input T in the first line, indicating the case number. Each case starts with two integers n , m(0<n,m<=10 5 ). The next line has n integers(0<=val<=10 5 ). The next m lines each has an operation: U A B(0<=A,n , 0<=B=10 5 ) OR Q A B(0<=A<=B< n)

离散化+线段树/二分查找/尺取法 HDOJ 4325 Flowers

放肆的年华 提交于 2020-01-11 10:02:15
题目传送门 题意:给出一些花开花落的时间,问某个时间花开的有几朵 分析:这题有好几种做法,正解应该是离散化坐标后用线段树成端更新和单点询问。还有排序后二分查找询问点之前总花开数和总花凋谢数,作差是当前花开的数量,放张图易理解: 还有一种做法用尺取法的思想,对暴力方法优化,对询问点排序后再扫描一遍,花开+1,花谢-1。详细看代码。 收获:一题收获很多:1. 降低复杂度可以用二分 2. 线段计数问题可以在端点标记1和-1 3. 离散化+线段树 终于会了:) ( 听说数据很水? ) 代码1:离散化+线段树 /************************************************ * Author :Running_Time * Created Time :2015-8-25 8:55:54 * File Name :F.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue>

HDU 4325 线段树离散化

这一生的挚爱 提交于 2020-01-11 04:59:34
线段树离散化 1.输入完所有数据,对开花时间离散化 2.区间更新,点查询,LAZY操作。。 View Code #include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> #include<vector> using namespace std; #define MAXN 51000 struct node { int left, right; int num; int sum; int lazy; }seg[500010]; int N, M; struct flower { int a,b; }p[101000]; int v[200010]; int hashx[201000]; void build(int l, int r, int root) { int mid = (l + r) / 2; seg[root].left = l; seg[root].right = r; seg[root].num = 0; seg[root].lazy = 0; seg[root].sum = 0; if( l == r ) { return; } build(l,mid,root*2); build(mid+1,r,root*2+1); seg[root].sum = seg[root*2]

权值线段树

一个人想着一个人 提交于 2020-01-10 14:33:04
权值线段树的功能有 查询x在整个区间出现的次数 查询[L,R]的数字出现的次数 所有数中出现次数第k大的数字 基于线段树和二分的思想 即 定义 \(int \ tree[maxn];\) tree[i]表示某段区间数字出现的次数 一般需要离散化操作 插入数据 void update(int l,int r,int rt,int x,int op){//插入op个x if(l == r){ tree[rt] += op; return; } int mid = (l + r) >> 1; if(x <= mid)update(lson,x,op); else update(rson,x,op); pushup(rt); } 查询x在整个区间出现的次数 int find(int l,int r,int rt,int x){//查询x在整个区间出现的次数 if(l == r)return tree[rt]; int mid = (l + r) >> 1; if(x <= mid)return find(lson,x); else return find(rson,x); } 查询[L,R]的数字出现的次数 int find2(int l,int r,int rt,int L,int R){//查询[L,R]的数字出现的次数 if(L <= l && r <= R)return tree

各种骚操作线段树

情到浓时终转凉″ 提交于 2020-01-10 10:28:56
线段树是世界上最美的数据结构(主要记录一些有意义的线段树.....特别是骚操作 1.uestc1425 Another LCIS http://acm.uestc.edu.cn/#/problem/show/360 题意:两种操作 对于一段区间的数加上c 查询最长连续上升序列 题解:彻底弄清楚区间更新lazy的含义 就是切水题 直接区间更新然后区间合并用点小技巧即可 #include <iostream> #include <algorithm> #include <cstdio> #define N 100005 using namespace std; typedef struct node{ int l;int r;int l1;int len1;int r1;int len2; int len;int flag; }node; node d[N<<2]; int a[N]; void up(int root){ d[root].l1=d[root<<1].l1;d[root].r1=d[root<<1|1].r1; if(d[root<<1].r1<d[root<<1|1].l1){ d[root].len=max(d[root<<1].len,max(d[root<<1].len2+d[root<<1|1].len1,d[root<<1|1].len)); if(d

线段树练习3

痴心易碎 提交于 2020-01-10 04:12:06
题目传送: http://codevs.cn/problem/1082/ 1082 线段树练习 3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 题目描述 Description 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和。 输入描述 Input Description 第一行一个正整数n,接下来n行n个整数, 再接下来一个正整数Q,每行表示操作的个数, 如果第一个数是1,后接3个正整数, 表示在区间[a,b]内每个数增加X,如果是2, 表示操作2询问区间[a,b]的和是多少。 pascal选手请不要使用readln读入 输出描述 Output Description 对于每个询问输出一行一个答案 样例输入 Sample Input 3 1 2 3 2 1 2 3 2 2 2 3 样例输出 Sample Output 9 数据范围及提示 Data Size & Hint 数据范围 1<=n<=200000 1<=q<=200000 分类标签 Tags 点此展开 代码 堆 #include<cstdio> #include<iostream> using namespace std; #define N 801000 #define mid ((l+r)>>1) #define lc (k