题目来自大神博客的线段树专题

http://www.notonlysuccess.com/index.php/segment-tree-complete/

hdu1166 敌兵布阵
题意:O(-1)
思路:O(-1)
线段树功能:update:单点增减 query:区间求和

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <utility>
#include <queue>
#include <stack>
using namespace std;
const int INF=<<;
const double eps=1e-;
const int N = ;
int sum[N<<],n,M; void add(int x,int v)
{
for(x+=M;x;x>>=)
sum[x]+=v;
}
int query(int l,int r)
{
int res=;
for(l=l+M-,r=r+M+;l^r^;l>>=,r>>=)
{
if(~l&) res+=sum[l^];
if(r&) res+=sum[r^];
}
return res;
}
void run()
{
scanf("%d",&n);
for(M=;M<=n+;M*=);
memset(sum,,sizeof(sum));
int x,y;
for(int i=;i<=n;++i)
{
scanf("%d",&x);
add(i,x);
}
char s[];
static int cas=;
printf("Case %d:\n",cas++);
while(scanf("%s",s)!=EOF && s[]!='E')
{
scanf("%d%d",&x,&y);
if(s[]=='Q') printf("%d\n",query(x,y));
else if(s[]=='A') add(x,y);
else add(x,-y);
}
} int main()
{
// freopen("case.txt","r",stdin);
int _;
scanf("%d",&_);
while(_--)
run();
return ;
}

PS: 第一次交RE了一次,原因是,题目的n范围是5*10^5,我只开了数组比这个数的两倍大一点。但是zkw要求范围是2的k次幂那样的,所以开数组要开大点吧

hdu1754 I Hate It
题意:O(-1)
思路:O(-1)
线段树功能:update:单点替换 query:区间最值

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <utility>
#include <queue>
#include <stack>
using namespace std;
const int INF=<<;
const double eps=1e-;
const int N = ; int mes[N<<],n,m,M; void update(int x,int v)
{
x+=M;mes[x]=v;
for(x>>=;x;x>>=)
mes[x]=max(mes[x<<],mes[x<<|]);
}
int query(int l,int r)
{
int res=;
for(l=l+M-,r=r+M+;l^r^;l>>=,r>>=)
{
if(~l&) res=max(res,mes[l^]);
if(r&) res=max(res,mes[r^]);
}
return res;
} void run()
{
for(M=;M<=n+;M<<=);
memset(mes,,sizeof(mes));
int x,y;
for(int i=;i<=n;++i)
{
scanf("%d",&x);
update(i,x);
}
char s[];
while(m--)
{
scanf("%s%d%d",s,&x,&y);
if(s[]=='Q') printf("%d\n",query(x,y));
else update(x,y);
}
} int main()
{
// freopen("case.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
run();
return ;
}

顺利1Y

hdu1394 Minimum Inversion Number
题意:求Inversion后的最小逆序数
思路:用O(nlogn)复杂度求出最初逆序数后,就可以用O(1)的复杂度分别递推出其他解。线段树是用在求最初逆序数上。递推方法详细在下面
线段树功能:update:单点增减 query:区间求和

递推: 因为题目总是把第一个数移到最后一个位置,所以原来比它小的数(和它构成逆序)在移动之后就不是逆序了,而原来比它大的数(不和它构成逆序)在移动之后就是逆序了,这样sum就变化了: Sum=sum-(low[a[i]])+(up[a[i]]);   显然在序列0,1,2,…..n-1中  比a[i]小的数的个数是 Low[a[i]]=a[i];  比a[i]大的数的个数是 up[a[i]]=n-a[i]-1;   题目要求是循环移动n次,那么只要写个for,把a[0],a[1],a[2]……a[n-1]都移动一遍,sum进行n次上面的公式运算,同时记录最小值,就是最小逆序数了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <utility>
#include <queue>
#include <stack>
using namespace std;
const int INF=<<;
const double eps=1e-;
const int N = ;
int sum[N<<],n,M;
int a[N]; inline void add(int x)
{
for(x+=M;x;x>>=)
++sum[x];
}
inline int query(int l,int r)
{
int res=;
for(l=l+M-,r=r+M+;l^r^;l>>=,r>>=)
{
if(~l&) res+=sum[l^];
if(r&) res+=sum[r^];
}
return res;
} void run()
{
int s=;
memset(sum,,sizeof(sum));
for(M=;M<=n+;M<<=);
for(int i=;i<=n;++i)
{
scanf("%d",&a[i]);
++a[i];//注意后面add的时候不能在0位置上add
if(a[i]!=n)
s+=query(a[i]+,n);
add(a[i]);
}
int ans=s;
for(int i=;i<=n;++i)
{
s = s + (n - a[i]) - (a[i] - );
if(s<ans) ans=s;
}
printf("%d\n",ans);
} int main()
{
// freopen("case.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
run();
return ;
}

一个要注意的地方是zkw不能在0位置操作,所以应该把a[i]都加一

hdu2795 Billboard
题意:h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子
思路:每次找到最大值的位子,然后减去L
线段树功能:query:区间求最大值的位子(直接把update的操作在query里做了)

跪了这个问题暂时没想到zkw怎么搞,这个是要根据当前区间最值来判断是去左子树还是右子树找,需要自顶向下的递归

//---------其他题目---------//

hdu4366

详细题解: hdu4366

需要用到线段树

单点更新,区间最值

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
const int N = ; struct _edge{
int to,next;
};
_edge edge[N*];
int ecnt,head[N];
void addedge(int u,int v)
{
edge[ecnt].to = v;
edge[ecnt].next = head[u];
head[u] = ecnt++;
}
struct node{
int id,a,b,l,r;
friend bool operator < (const node &a, const node &b)
{
return a.a>b.a;
}
}; int n,m,M;
int zkw[N*][];
node man[N];
int ans[N];
int dfscnt;
void dfs(int u,int fa)
{
man[u].l = dfscnt++;
for(int e=head[u];e!=-;e=edge[e].next)
{
int &v = edge[e].to;
if(v==fa) continue;
dfs(v,u);
}
man[u].r = dfscnt++;
} void add(int x,int a,int b)
{
for(x+=M;x;x>>=)
if(zkw[x][]<a)
zkw[x][]=a,zkw[x][]=b;
}
int query(int l,int r)
{
int a,b;
a=b=-;
for(l=l+M-,r=r+M+;l^r^;l>>=,r>>=)
{
if(~l& && zkw[l^][]>a) a=zkw[l^][],b=zkw[l^][];
if(r& && zkw[r^][]>a) a=zkw[r^][],b=zkw[r^][];
}
return b;
} void run()
{
scanf("%d%d",&n,&m);
memset(head,-,sizeof(head));
ecnt=;
int a,b,c;
for(int i=;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a,i);
addedge(i,a);
man[i].a=c;
man[i].b=b;
man[i].id=i;
}
dfscnt=;
dfs(,-);
// for(int i=0;i<n;i++)
// printf("%d %d %d\n",i,man[i].l,man[i].r);
sort(man+,man+n); for(M=;M<=dfscnt+;M*=);
memset(zkw,-,sizeof(zkw)); stack<int> stk;
stk.push();
ans[man[].id]=-;
for(int i=;i<n;i++)
{
if(man[i].a!=man[i-].a)
{
while(!stk.empty())
{
int u = stk.top(); stk.pop();
add(man[u].l,man[u].b,man[u].id);
add(man[u].r,man[u].b,man[u].id);
}
}
stk.push(i);
ans[man[i].id] = query(man[i].l,man[i].r);
}
while(m--)
{
scanf("%d",&a);
printf("%d\n",ans[a]);
}
} int main()
{
freopen("case.txt","r",stdin);
int _;
scanf("%d",&_);
while(_--)
run();
return ;
}

zkw线段树专题的更多相关文章

  1. zkw线段树模板题

    学了zkw线段树,觉得没什么必要刷专题的吧(切不动啊).. 那先放一个模板题吧(我绝不会和你说搬了一道树状数组模板题的!!!) 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加 ...

  2. ZKW线段树

    简介 zkw线段树虽然是线段树的另一种写法,但是本质上已经和普通的递归版线段树不一样了,是一种介于树状数组和线段树中间的存在,一些功能上的实现比树状数组多,而且比线段树好写且常数小. 普通线段树采用从 ...

  3. zkw线段树详解

    转载自:http://blog.csdn.net/qq_18455665/article/details/50989113 前言 首先说说出处: 清华大学 张昆玮(zkw) - ppt <统计的 ...

  4. BZOJ3173 TJOI2013最长上升子序列(Treap+ZKW线段树)

    传送门 Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input ...

  5. 【POJ3468】【zkw线段树】A Simple Problem with Integers

    Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...

  6. HDU 4366 Successor(树链剖分+zkw线段树+扫描线)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...

  7. [SinGuLaRiTy] ZKW线段树

    [SinGuLaRiTy-1007] Copyrights (c) SinGuLaRiTy 2017. All Rights Reserved. 关于ZKW线段树 Zkw线段树是清华大学张昆玮发明非递 ...

  8. 数据结构3——浅谈zkw线段树

    线段树是所有数据结构中,最常用的之一.线段树的功能多样,既可以代替树状数组完成"区间和"查询,也可以完成一些所谓"动态RMQ"(可修改的区间最值问题)的操作.其 ...

  9. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

随机推荐

  1. python 基础 9.1 连接数据库

    二.数据库连接 MySQLdb 提供了connect 方法用来和数据库建立连接,接收数个参数,返回连接对象: #/usr/bin/python #coding=utf-8 #@Time   :2017 ...

  2. kibana 查询语法

    根据某个字段查询 精确匹配: agent:"Mozilla/5.0" 如果不带双引号,只要包含指定值就可以搜索到 agent:Mozilla/5.0 如果是数值类型没有以上区别 数 ...

  3. python书写日志的重要性?

    转自:https://blog.csdn.net/weixin_43063753/article/details/82899395 程序为什么要写日志?#为了能够在程序在运行过程中记录错误,方便维护, ...

  4. BZOJ1217: [HNOI2003]消防局的设立

    BZOJ1217: [HNOI2003]消防局的设立 Description 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地. 起初为了节约材料,人类只修建了n-1条道路来连接这些基地 ...

  5. Django框架打印orm转换过程中的sql_模型层

    LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBU ...

  6. win7计划任务定时执行PHP脚本设置图解

    做php开发的朋友有时候会希望自己的电脑能每天定时的运行一下某个脚本,但定时执行php脚本这种概念似乎多半是在linux中才提到,下面这篇文章主要和大家分享一下在win7下如何设置计划任务,以实现定时 ...

  7. android的GPS代码分析JNI如何HAL之间如何设置回调函数【转】

    本文转载自:http://blog.csdn.net/kmesg/article/details/6531577 本文只关注JNI和HAL的接口部分 在jni的android_location_Gps ...

  8. matlab之结构体数组struct

    以下内容来自于:https://blog.csdn.net/u010999396/article/details/54413615/ 要在MALTAB中实现比较复杂的编程,就不能不用struct类型. ...

  9. jquery 3D分页翻转滑块

    jquery 3D分页翻转滑块,jquery分页,jquery插件,jquery,3D翻转,css3分页,360度旋转,网页特效代码3D分页翻转滑块是一款使用网格样式与滑块效果分页的特效.

  10. BZOJ 2101 [Usaco2010 Dec]Treasure Chest 藏宝箱:区间dp 博弈【两种表示方法】【压维】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2101 题意: 共有n枚金币,第i枚金币的价值是w[i]. 把金币排成一条直线,Bessie ...