zkw线段树专题
题目来自大神博客的线段树专题
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线段树专题的更多相关文章
- zkw线段树模板题
学了zkw线段树,觉得没什么必要刷专题的吧(切不动啊).. 那先放一个模板题吧(我绝不会和你说搬了一道树状数组模板题的!!!) 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加 ...
- ZKW线段树
简介 zkw线段树虽然是线段树的另一种写法,但是本质上已经和普通的递归版线段树不一样了,是一种介于树状数组和线段树中间的存在,一些功能上的实现比树状数组多,而且比线段树好写且常数小. 普通线段树采用从 ...
- zkw线段树详解
转载自:http://blog.csdn.net/qq_18455665/article/details/50989113 前言 首先说说出处: 清华大学 张昆玮(zkw) - ppt <统计的 ...
- BZOJ3173 TJOI2013最长上升子序列(Treap+ZKW线段树)
传送门 Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input ...
- 【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 ...
- HDU 4366 Successor(树链剖分+zkw线段树+扫描线)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...
- [SinGuLaRiTy] ZKW线段树
[SinGuLaRiTy-1007] Copyrights (c) SinGuLaRiTy 2017. All Rights Reserved. 关于ZKW线段树 Zkw线段树是清华大学张昆玮发明非递 ...
- 数据结构3——浅谈zkw线段树
线段树是所有数据结构中,最常用的之一.线段树的功能多样,既可以代替树状数组完成"区间和"查询,也可以完成一些所谓"动态RMQ"(可修改的区间最值问题)的操作.其 ...
- 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题
“队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄> 线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...
随机推荐
- java jdbc oracle ORA-01795: 列表中的最大表达式数为 1000
在操作SQL中存在In的数量如果超过1000条会提示 ORA-01795: 列表中的最大表达式数为 1000 归纳有几种方式出现的: 第一种是:我在上一个 [jdbc 同时执行 查询和删除操]作中 ...
- Mysql代码建外键问题
用下面代码建外键 运行之后 没有提示错误 但是打开建好的表格 外键并没有建立上 打开外键栏 里面并没有外键 在从表设置了外键列里面输入东西没有任何限制 成功建立应该是下面这样 什么情况???????? ...
- 最近两周我们接触到的两种线上抓娃娃机的技术实现方案(一种RTSP/一种RTMP)
线上抓娃娃机需求 最近线上抓娃娃机的项目火爆了,陆陆续续几十款线上抓娃娃机上架,还有一大波正在开发上线中,各大视频云提供商都在蹭热度发布自己的线上抓娃娃机方案,综合了一下,目前线上抓娃娃机的视频需求无 ...
- 高性能流媒体服务器EasyDSS前端重构(三)- webpack + vue + AdminLTE 多页面引入 element-ui
接上篇 接上篇<高性能流媒体服务器EasyDSS前端重构(二) webpack + vue + AdminLTE 多页面提取共用文件, 优化编译时间> 本文围绕着实现EasyDSS高性能流 ...
- mysql系列之8.mysql高可用 (keepalived)
环境: centos6.5_x64 准备: 两台mysql机器 主1 master: 192.168.32.130 主2 backup: 192.168.32.131 VIP: 192.168.3 ...
- Halcon下载、安装
下载地址: 官网:http://www.halcon.com/halcon/download/ Halcon学习网:http://www.ihalcon.com/read.php?tid=56 { 最 ...
- 服务器安装tensorflow导入模块报错Illegal instruction (core dumped)
在ubuntu上安装tensorflow后导入模块显示Illegal instruction (core dumped) 服务器的版本是Ubuntu 16.04.5 降低版本,成功导入模块 pip3 ...
- gradlew tasks
D:\AndroidWorkSpace\Qi\LocalM>gradlew tasks > Configure project : AAAA > Configure project ...
- packstack快速安装
1 安装软件库 更新安装的软件包,命令如下: sudo yum update -y 建立RDO库,命令如下: sudo yum install -y https://rdo.fedorapeople. ...
- American Heritage usaco
基础题,主要思路是找到根,然后分别递归即可: #include<iostream> #include<cstring> #include<string> #incl ...