A - 一棵简单的线段树

A[1...n]初始全为0.

1. 给两个数p 和 x(1≤p≤n),单点更新 A[p] <- x

2. 给两个数L和R (1≤L<R≤n),  L到R区间里这几个数去掉一个最大值和一个最小值后剩下的数的和是多少。用到了max, min, sum

 #include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e6+;
#define LL long long
#define INF 0x7fffffff int n,a[maxn],q; struct node
{
int l,r,mx,mn;
long long sum;
void update(long long x) {sum=x;mx=x;mn=x;}
}tree[maxn*]; void push_up(int x)
{
tree[x].sum=tree[x<<].sum+tree[x<<|].sum;
tree[x].mx=max(tree[x<<].mx,tree[x<<|].mx);
tree[x].mn=min(tree[x<<].mn,tree[x<<|].mn);
} void build(int x,int l,int r)
{
tree[x].l=l,tree[x].r=r;
tree[x].sum=,tree[x].mx=,tree[x].mn=;
if(l==r)
{
tree[x].sum=tree[x].mx=tree[x].mn=a[l];
}
else
{
int mid = (l+r)/;
build(x<<,l,mid);
build(x<<|,mid+,r);
push_up(x);
}
} void update(int x,int pos,long long val)
{
int L =tree[x].l, R = tree[x].r;
if(L==pos&&R==pos)
{
tree[x].update(val);
}
else
{
int mid = (L+R)/;
if(mid>=pos)update(x<<,pos,val);
if(pos>mid)update(x<<|,pos,val);
push_up(x);
}
} long long query(int x,int l,int r)
{
int L =tree[x].l, R = tree[x].r;
if(l<=L&&R<=r)
return tree[x].sum;
else
{
long long ans=;
int mid = (L+R)/;
if(mid>=l)ans+=query(x<<,l,r);
if(r>mid)ans+=query(x<<|,l,r);
push_up(x);
return ans;
}
} int query_max(int x,int l,int r)
{
int L =tree[x].l, R = tree[x].r;
if(l<=L&&R<=r)
return tree[x].mx;
else
{
int ans=-1e9-;
int mid = (L+R)/;
if(mid>=l)ans=max(ans,query_max(x<<,l,r));
if(r>mid)ans=max(ans,query_max(x<<|,l,r));
push_up(x);
return ans;
}
} int query_min(int x,int l,int r)
{
int L =tree[x].l, R = tree[x].r;
if(l<=L&&R<=r)
return tree[x].mn;
else
{
int ans=1e9+;
int mid = (L+R)/;
if(mid>=l)ans=min(ans,query_min(x<<,l,r));
if(r>mid)ans=min(ans,query_min(x<<|,l,r));
push_up(x);
return ans;
}
} int main() {
scanf("%d",&n);
for(int i=;i<=n;i++)a[i]=;
build(,,n);
scanf("%d",&q);
for(int i=;i<=q;i++)
{
int x,y,o;
scanf("%d%d%d",&o,&x,&y);
if(o==)update(,x,y);
else
{
long long sum=query(,x,y);
int mx=query_max(,x,y);
int mn=query_min(,x,y);
printf("%lld\n",sum-mx-mn);
}
}
return ;
}

B - 一棵普通的线段树

A[1...n]初始全为0。

一棵裸的区间修改、区间查询的线段树

1. 区间加v

2. 区间求和

区间修改(带lazy 标记)、区间查询的线段树可以在 O(log n) 的时间内维护区间和
 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e6+;
#define LL long long
#define INF 0x7fffffff int n,q,a[maxn]; struct node{
int l, r;
LL sum, lazy;
void update(int x) {
sum += 1LL*(r-l+)*x;
lazy += x;
}
}tree[maxn*]; void push_up(int x) {
tree[x].sum = tree[x<<].sum + tree[x<<|].sum;
} void push_down(int x) {
int lazy = tree[x].lazy;
if(lazy) {
tree[x<<].update(lazy);
tree[x<<|].update(lazy);
tree[x].lazy = ;
}
} void build(int x, int l, int r) {
tree[x].l = l, tree[x].r = r;
tree[x].sum = tree[x].lazy = ;
if(l == r) {
tree[x].sum = a[l];
}
else {
int mid = (l+r) / ;
build(x<<, l, mid);
build(x<<|, mid+, r);
push_up(x);
}
} void update(int x, int l, int r, int val) {
int L = tree[x].l, R = tree[x].r;
if(l <= L && R <= r) {
tree[x].update(val);
}
else {
push_down(x);
int mid = (L+R) / ;
if(mid >= l) update(x<<, l, r, val);
if(r > mid) update(x<<|, l, r, val);
push_up(x);
}
} LL query(int x, int l, int r) {
int L = tree[x].l, R = tree[x].r;
if(l <= L && R <= r) return tree[x].sum;
else {
push_down(x);
int mid = (L+R) / ;
LL ans = ;
if(mid >= l) ans += query(x<<, l, r);
if(r > mid) ans += query(x<<|, l, r);
push_up(x);
return ans;
}
} int main() {
scanf("%d",&n);
for(int i=;i<=n;i++)a[i]=;
build(,,n);
scanf("%d",&q);
for(int i=;i<=q;i++)
{
int o,l,r,val;
scanf("%d%d%d%d",&o,&l,&r,&val);
if(o==)update(,l,r,val);
else printf("%lld\n",query(,l,r));
}
return ;
}

C - 一棵像样的线段树

假设每个Ci = i , bn最大为n+1。

对于每个Ci,相当于询问b[i-ci] 到 b[i-1] 区间内最小未出现的数。

可以设s[x] 为x最后出现的位置。对于每个Ci,我们可以得到左区间 i - Ci;

s[1]= 0 , 其他位置初始化-1(其他值都未出现过,所以都满足s[x] < i - ci )

凡是s[x] < i - Ci 的x均未在区间内出现过,那么我们只要找出最小的x,满足:s[x] < i - ci 即可。 

可以用线段树维护s[x] ,1 <= x <= n+1 , 区间的最小值。

每次给出左区间 i - ci ,就从最大的区间查询,如果左子树的最小值>=i-ci,就递归访问右子树,否则访问左子树。

最终区间长度为1时,l(或r)即为答案。

总结:可以发现b数组最多就是1到n,那么对于1到n开一棵线段树,每个结点储存当前数出现的最后的位置。因为我们要求的是 i-ci到i-1的范围内没有出现过的第一个数,

那么我们现在储存了每个数出现的最后的位置,那么我们就找一个这个位置不在i-ci到i-1的范围内且最小的数即可。因为我们线段树是默认1到n即从小到大,所以即尽可能地往左子树找,

 #include <bits/stdc++.h>
using namespace std; const int N = 1e6+;
const int maxn = N<<; int n,a[N];
int tree[maxn];
int ans[N]; void update_tree(int a, int b, int pos, int node, int value) {
if(a>b || a>pos || b<pos) return;
if(a==b) {
tree[node]=value;
return;
}
update_tree(a,(a+b)>>,pos,node<<,value);
update_tree(((a+b)>>)+,b,pos,(node<<)|,value);
tree[node]=min(tree[node<<],tree[(node<<)|]);
} int query_tree(int a, int b, int node, int value) {
if(a==b) return a;
if(tree[node<<]<value) return query_tree(a,(a+b)>>,node<<,value);
else return query_tree(((a+b)>>)+,b,(node<<)|,value);
} int main() {
int i;
scanf("%d", &n);
for(i=;i<=n;i++)
{
scanf("%d", &a[i]);
}
for(i=;i<=n;i++)
{
if(i==)update_tree(,,,,);
else update_tree(,,ans[i],,i);
int l=i-a[i]+;
ans[i+]=query_tree(,,,l);
}
for(i=;i<=n+;i++)
if(i<n+)printf("%d ", ans[i]);
else printf("%d\n", ans[i]); return ;
} #include <bits/stdc++.h>
using namespace std; const int N = 1e6+;
const int maxn = N<<; int n, a[N], ans[N]; struct node
{
int l,r;
int min_left;
void update(int value){min_left=value;}
}tree[maxn]; void push_up(int x)
{
tree[x].min_left = min(tree[x<<].min_left,tree[x<<|].min_left);
} void build(int x,int l,int r)
{
tree[x].l=l,tree[x].r=r;
if(l==r)
{
tree[x].min_left = -;
}
else
{
int mid = (l+r)/;
build(x<<,l,mid);
build(x<<|,mid+,r);
push_up(x);
}
}
void update_tree(int x, int l, int r, int pos, int value) {
if(l>r || l>pos || r<pos) return;
if(l==r)
{
tree[x].update(value);
}
else
{
int mid = (l+r)/;
if(pos<=mid)update_tree(x<<,l,mid,pos,value);
if(pos<=r)update_tree(x<<|,mid+,r,pos,value);
push_up(x);
}
} int query_tree(int x, int l, int r, int value) {
if(l==r) return l;
int mid = (l+r)/;
if(tree[x<<].min_left<value) return query_tree(x<<,l,mid,value);
else return query_tree(x<<|,mid+,r,value);
} int main() {
int i;
scanf("%d", &n);
for(i=;i<=n;i++)
{
scanf("%d", &a[i]);
}
build(,,);
for(i=;i<=n;i++)
{
if(i==)update_tree(,,,,);
else update_tree(,,,ans[i],i);
int l=i-a[i]+;
ans[i+]=query_tree(,,,l);
}
for(i=;i<=n+;i++)
if(i<n+)printf("%d ", ans[i]);
else printf("%d\n", ans[i]); return ;
}

D - 一棵复杂的线段树

A[1...n]为1到n的一个全排列

对[L,R]区间,升序排序或降序排序

排完后查找第K个数

思路:线段树+二分答案

结果只要求a[k]的值,并且a数列是1-n的一个全排列,那么可以二分答案。 
排序过程不好想,假设mid为答案,将>mid的设为1,<=mid的设为0。
当对 [L,R] 区间进行排序时, 
1. 先求出区间内1的个数。 
2. 区间全置为0. 
3. 升序排序时,将最后c个数 ( [R-c+1, R] ) 置为1. 
4. 降序排序时,将前c个数( [L, L + c - 1] )置为1. 
所有操作进行结束后,如果 [k, k] == 1 说明 a[k] > mid ( li = mid + 1 ) , 为 0 说明 a[k] <= mid ( ri = mid ) 。

 #include <bits/stdc++.h>
using namespace std;
const int AX = 1e5+;
int lazy[AX<<];
int s[AX<<];
int a[AX];
int op[AX];
int l[AX];
int r[AX];
int n,k;
int tot; void push_down( int rt , int l , int r ){
if( lazy[rt] != - ){
int mid = ( l + r ) >> ;
s[rt<<] = ( mid - l + ) * lazy[rt] ;
s[rt<<|] = ( r - mid ) * lazy[rt];
lazy[rt<<] = lazy[rt];
lazy[rt<<|] = lazy[rt];
lazy[rt] = -;
}
return ;
} void push_up( int rt ){
s[rt] = s[rt<<] + s[rt<<|];
return ;
} void build( int l , int r , int rt , int v ){
lazy[rt] = -;
if( l == r ){
s[rt] = ( a[l] > v ) ;
return ;
}
int mid = ( l + r ) >> ;
build( l , mid , rt << , v );
build( mid + , r , rt << | , v);
push_up(rt);
} void update( int L , int R , int v , int l , int r , int rt ){
if( L <= l && r <= R ){
s[rt] = v * ( r - l + );
lazy[rt] = v;
return;
}
push_down(rt,l,r);
int mid = ( l + r ) >> ;
if( L <= mid ) update( L , R , v , l , mid , rt << );
if( R > mid ) update( L , R , v , mid + , r , rt << | );
push_up(rt);
} int query( int L , int R , int l , int r , int rt ){
if( L <= l && r <= R ){
return s[rt];
}
push_down(rt,l,r);
int ans = ;
int mid = ( l + r ) >> ;
if( L <= mid ) ans += query( L , R , l , mid, rt << );
if( R > mid ) ans += query( L , R , mid + , r , rt << | );
return ans ;
} int main(){
scanf("%d%d",&n,&k);
for( int i = ; i <= n ; i++ ){
scanf("%d",&a[i]);
}
int m ;
scanf("%d",&m);
for( int i = ; i < m ; i++ ){
scanf("%d%d%d",&op[i],&l[i],&r[i]);
}
int li = , ri = n ;
while( li < ri ){ // [li,ri]
int mid = ( li + ri ) >> ;
build( , n , , mid );
for( int i = ; i < m ; i++ ){
int L = l[i];
int R = r[i];
int c = query( L , R , , n , ); // 区间查询 > mid 的个数
update( L , R , , , n , ); // 区间更新 为0
if( op[i] ){
if( L <= L + c - ){
update( L , L + c - , , , n , ); // 区间更新
}
}else{
if( R - c + <= R ){
update( R - c + , R , , , n , ); // 区间更新
}
}
}
if( query( k , k , , n , )) li = mid + ; // 单点查询
else ri = mid;
}
printf("%d\n",li);
return ;
}

最新文章

  1. (转载)SQL去除回车符,换行符,空格和水平制表符
  2. 实验二 简易版C语言文法
  3. System.StackOverflowException的一个例子(转)
  4. Xshell 登录 AWS CentOS 出现“所选择的用户秘钥未在远程主机上注册“,最终解决办法!
  5. 设置Android studio内容的主题
  6. ember.js:使用笔记10 常用方法
  7. C# WebApi传参之Get请求-AJAX
  8. Java基础知识强化之IO流笔记68:Properties和IO流集合使用
  9. IRQL_NOT_LESS_OR_EQUAL的问题最终算攻克了
  10. CentOS7--64安装python的psutil模块
  11. 如何在Ubuntu 11.10上连接L2TP VPN
  12. Nexus搭建私服 学习
  13. C#计算表达式(仿计算器功能)
  14. JAVASCRIPT 调用 OCX 的那些坑
  15. 调用支付宝第三方接口(沙箱环境) SpringMVC+Maven
  16. BZOJ3224/LOJ104 普通平衡树 pb_ds库自带红黑树
  17. Delphi10.2 Tokyo试用(1)
  18. galera+mycat高可用集群部署
  19. API--ResponseBody-类
  20. LeetCode第[20]题(Java):Valid Parentheses

热门文章

  1. vue之递归组件实现树形目录
  2. VC操作excel
  3. php无法连接mysql问题解决方法总结
  4. git与eclipse集成之保存快照
  5. 阿里云服务器上通过Docker部署redmine
  6. 031_keepalive+nginx保证nginx高可用
  7. Bootstrap 固定底部导航栏菜单
  8. 点9图 Android设计中如何切图.9.png
  9. Webform中&lt;%%&gt;
  10. js跳转页面(转)