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线段树+权值线段树+主席树及一些例题
“队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄> 线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...
随机推荐
- wait() 区别 sleep()
wait() notify() notifyAll() wait和notify方法必须写在synchronized方法内,即在调用wait和notify方法前,需先获得对象锁: 调用wait方法则释放 ...
- 【C#图解】PictureBox.SizeMode 属性(转)
PictureBoxSizeMode.Normal: 默认情况下,在 Normal 模式中,Image 置于 PictureBox 的左上角,凡是因过大而不适合 PictureBox 的任何图像部分都 ...
- Wix Burn:如何将32位和64位的安装包制作成一个安装包
由于Windows Installer不是平台独立的(即区分32-bit和64-bit),因此用Wix制作的安装包在编译不能像.net应用那样采用Any CPU编译,而必须制定是目标Platform是 ...
- 我的Java开发学习之旅------>计算从1到N中1的出现次数的效率优化问题
有一个整数n,写一个函数f(n),返回0到n之间出现的"1"的个数.比如f(1)=1:f(13)=6,问一个最大的能满足f(n)=n中的n是什么? 例如:f(13)=6, 因为1, ...
- 使用 Nginx 提升网站访问速度(转)
Nginx 简介 Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. Nginx 是由 Ig ...
- 《转》使用nginx和php实时产生缩略图
在做自动静态化的时候,突然想到下面这个场景,也给出了解决方法.亲,真的很实用,耐心看下去. 当我从后台上传一个截图之后,480*800的截图之后,当时就没有压缩出320*480的小缩略图.好吧 ...
- gradle 跳过junitTest的方法
Web项目中不长会写JunitTest,但也会写.gradle build的时候回执行test 这项task.如果想跳过,通常有几种方法: 1.在build.gradle 文件中禁用task test ...
- 【Java 语言生态篇】Junit 测试单元
01 概述 JUnit是一个由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework).Junit测试是白盒测试.JUn ...
- nodejs中的子进程,深入解析child_process模块和cluster模块
Node.js的进程管理 node遵循的是单线程单进程的模式,node的单线程是指js的引擎只有一个实例,且在nodejs的主线程中执行,同时node以事件驱动的方式处理IO等异步操作.node的 ...
- MSSQL2005外网IP的1433端口开启方法
打开SQL Server Configuration Manager,在SQL server配置管理器展开SQL server 2005网络配置-->SQLEXPRESS 的协议-->双击 ...