【Homework】LCA&RMQ
我校是神校,作业竟然选自POJ,难道不知道“珍爱生命 勿刷POJ”么?
所有注明模板题的我都十分傲娇地没有打,于是只打了6道题(其实模板题以前应该打过一部分但懒得找)(不过感觉我模板还是不够溜要找个时间刷一发)。
没注明模板题的都是傻逼题,其实也是模板题。
题目大致按照傻逼程度从大到小排序。
POJ 3264 Balanced Lineup
题意:n个数,m个询问,每次问max[l,r]-min[l,r]。
题解:这道题竟然没标注模板题真是惊讶...
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=5e4+; int g[maxn][],h[maxn][];
int n,m; void get(){
for(int j=;(<<j)<=n;j++)
for(int i=;i+(<<j)-<=n;i++)
g[i][j]=min(g[i][j-],g[i+(<<(j-))][j-]),
h[i][j]=max(h[i][j-],h[i+(<<(j-))][j-]);
} int ask(int l,int r){
int k=;
while(<<(k+)<=r-l+) k++;
int Min=min(g[l][k],g[r-(<<k)+][k]);
int Max=max(h[l][k],h[r-(<<k)+][k]);
return Max-Min;
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%d",&h[i][]);
g[i][]=h[i][];
}
get(); int l,r;
for(int i=;i<=m;i++){
scanf("%d%d",&l,&r);
printf("%d\n",ask(l,r));
}
return ;
}
POJ 3368 Frequent values
题意:n个数组成一个不降序列,m个询问,每次问[l,r]出现次数最多的数。
题解:预处理把相同的数变成一块,查询时二分lr所在块,这部分求RMQ,lr不在块内的单独处理。
这种划分块的细节及边界一定要想清了,手一抖就会错。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e5+; int a[maxn],b[maxn],c[maxn],t[maxn],tot;
int h[maxn][];
int n,m; void clear(){
memset(h,,sizeof(h));
memset(a,,sizeof(a));
memset(b,,sizeof(b));
memset(c,,sizeof(c));
memset(t,,sizeof(t));
tot=;
} void get(){
for(int i=;i<=tot;i++) h[i][]=t[i];
for(int j=;(<<j)<=tot;j++)
for(int i=;i+(<<j)-<=tot;i++)
h[i][j]=max(h[i][j-],h[i+(<<(j-))][j-]);
} int ask(int l,int r){
if(l>r) return ;
int k=;
while(<<(k+)<=r-l+) k++;
return max(h[l][k],h[r-(<<k)+][k]);
} int main(){ while(scanf("%d%d",&n,&m)!=EOF){
if(n==) break;
clear(); for(int i=;i<=n;i++){
scanf("%d",&a[i]);
if(i==||a[i]!=a[i-]){
++tot;
b[tot]=i;
t[tot]=;
c[tot-]=i-;
}
else t[tot]++;
}
c[tot]=n;
b[tot+]=n+;
get(); int ll,rr,l,r;
for(int i=;i<=m;i++){
scanf("%d%d",&ll,&rr);
l=lower_bound(b+,b+tot+,ll)-b;
r=upper_bound(c+,c+tot+,rr)-c-;
if(r==l-){
printf("%d\n",rr-ll+);
continue;
}
int ans=max(b[l]-ll,rr-c[r]);
ans=max(ans,ask(l,r));
printf("%d\n",ans);
}
}
}
POJ 2763 Housewife Wind
题意:n个节点的树,两个操作,一询问(u,v)距离,二修改某条边边权。
题解:树上的路径长度,很快反应dist[u]+dist[v]-2*dist[lca],这个就像前缀和表示序列一样。
修改一条边对单点到跟链的影响很好统计,利用dfs序+树状数组即可。
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1e5+,POW=; int p[maxn][POW],pw[maxn],que[maxn],idx[maxn],l[maxn],r[maxn],dep[maxn];
int e[maxn*],w[maxn*],nxt[maxn*],head[maxn],tot;
ll d[maxn],c[maxn];
int n,m,s,clock; void dfs(int u,ll dist){
++clock;
que[clock]=u;
l[u]=clock;
d[u]=dist;
dep[u]=dep[p[u][]]+; for(int i=;i<POW;i++) p[u][i]=p[p[u][i-]][i-]; for(int i=head[u];i;i=nxt[i]){
int v=e[i];
if(v==p[u][]) continue;
p[v][]=u,pw[v]=w[i];
dfs(v,dist+w[i]);
}
r[u]=clock;
} int LCA(int u,int v){
if(dep[u]>dep[v]) swap(u,v);
if(dep[u]<dep[v]){
int del=dep[v]-dep[u];
for(int i=;i<POW&&del;i++)
if(del&(<<i)) v=p[v][i];
}
if(u==v) return u;
for(int i=POW-;i>=;i--)
if(p[u][i]!=p[v][i]) u=p[u][i],v=p[v][i];
u=p[u][];
return u;
} void add(int x,int w){
for(int i=x;i>;i-=(i&-i)) c[i]+=w;
}
ll sum(int x){
ll ret=;
for(int i=x;i<=n;i+=(i&-i)) ret+=c[i];
return ret;
} void adde(int u,int v,int g){
++tot;
e[tot]=v,w[tot]=g;
nxt[tot]=head[u];
head[u]=tot;
} int main(){
scanf("%d%d%d",&n,&m,&s);
int u,v,g;
for(int i=;i<n;i++){
scanf("%d%d%d",&u,&v,&g);
adde(u,v,g);
adde(v,u,g);
} dfs(,);
for(int i=;i<=n;i++) idx[que[i]]=i; int x,num;
for(int i=;i<=m;i++){
scanf("%d",&x);
if(x==){
scanf("%d",&u);
int lca=LCA(s,u);
ll ans=d[u]+d[s]-*d[lca];
ans+=(sum(idx[u])+sum(idx[s])-*sum(idx[lca]));
printf("%lld\n",ans);
s=u;
}
else{
scanf("%d%d",&num,&g);
u=e[num*-],v=e[num*];
if(p[v][]!=u) swap(u,v);
add(l[v]-,pw[v]-g);
add(r[v],-pw[v]+g);
pw[v]=g;
}
}
return ;
}
POJ 3728 The merchant
题意:n个节点带权的树,m个询问,问从x->y的路径上max-min为多少,且路径上max位置必须在min位置之前。
题解:分治的思想,我们怎么合并左右两段路?①maxmin全在路1;②全在路2;③max在路1,min在路二。
保存四个量up[x],down[x],min[x],max[x]。
分别代表x->p最优解,p->x最优解,x-p路径上最小值,x-p路径上最大值。
当然还是要用到LCA,如果用trajan就在并查集合并时处理,倍增就更好处理了。
tarjan要想清,要注意答案在lca处统计,下次再码一发倍增。
听说其他同学写了180+行,十分好奇写了些什么>.<
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=5e4+; int up[maxn],down[maxn],Min[maxn],Max[maxn];
int n,m; int heade[maxn],e[maxn*],nxte[maxn*];
void adde(int u,int v,int k){
e[k]=v,nxte[k]=heade[u];
heade[u]=k;
} int headq[maxn],q[maxn*],nxtq[maxn*];
void addq(int u,int v,int k){
q[k]=v,nxtq[k]=headq[u];
headq[u]=k;
} int heada[maxn],a[maxn*],nxta[maxn*],tot;
void adda(int u,int num){
++tot;
a[tot]=num,nxta[tot]=heada[u];
heada[u]=tot;
} int p[maxn],vis[maxn],ans[maxn];
void find(int x){
if(p[x]==x) return;
find(p[x]);
up[x]=max(up[x],max(up[p[x]],Max[p[x]]-Min[x]));
down[x]=max(down[x],max(down[p[x]],Max[x]-Min[p[x]]));
Min[x]=min(Min[x],Min[p[x]]);
Max[x]=max(Max[x],Max[p[x]]);
p[x]=p[p[x]];
} void LCA(int u){
vis[u]=;
for(int i=headq[u];i;i=nxtq[i])
if(vis[q[i]]){
int v=q[i];
find(v);
int lca=p[v];
adda(lca,i);
} for(int i=heade[u];i;i=nxte[i])
if(!vis[e[i]]){
int v=e[i];
LCA(v);
p[v]=u;
} for(int i=heada[u];i;i=nxta[i]){
int k=a[i],x,y;
if(k%==) x=q[k+],y=q[k];
else x=q[k],y=q[k-];
find(x),find(y);
k=(k+)/;
ans[k]=max(up[x],max(down[y],Max[y]-Min[x]));
}
} int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&Min[i]);
Max[i]=Min[i];
p[i]=i;
} int u,v;
for(int i=;i<n;i++){
scanf("%d%d",&u,&v);
adde(u,v,i*-);
adde(v,u,i*);
} scanf("%d",&m);
for(int i=;i<=m;i++){
scanf("%d%d",&u,&v);
addq(u,v,i*-);
addq(v,u,i*);
} LCA();
for(int i=;i<=m;i++)
printf("%d\n",ans[i]); return ;
}
POJ 3417 Network
题意:n个节点的树,加入m条新边,现在删除一条旧边一条新边使得新的到的图不再联通,求方案数。
题解:乍一看没什么思路,画个图就很好想了。
加入(u,v)这条边,会形成一个u-v-lca的环。
考虑每一条旧边,如果所在环个数为0,那么另一条边怎么选都可以,贡献为m;如果为1,那么必须删除使它形成环的新边,贡献为1;如果>1,弃疗,贡献为0;
然后是常用技巧,打标记然后树形dp一遍。
f[u]++; f[v]++; f[lca]-=2;
对于统计边是这样,如果是统计点就是f[lca]--, f[p[lca]]--, 如Bzoj 松鼠的新家。
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=1e5+; int vis[maxn],f[maxn],p[maxn];
int e[maxn*],nxte[maxn*],heade[maxn],tote;
int q[maxn*],nxtq[maxn*],headq[maxn],totq;
int n,m; int find(int x){return p[x]==x?x:p[x]=find(p[x]);} void adde(int u,int v){
tote++;
e[tote]=v;
nxte[tote]=heade[u];
heade[u]=tote;
} void addq(int u,int v){
totq++;
q[totq]=v;
nxtq[totq]=headq[u];
headq[u]=totq;
} void tarjan(int u){
vis[u]=;
for(int i=headq[u];i;i=nxtq[i])
if(vis[q[i]]){
int v=q[i],lca=find(v);
f[u]++,f[v]++;
f[lca]-=;
} for(int i=heade[u];i;i=nxte[i])
if(!vis[e[i]]){
int v=e[i];
tarjan(v);
p[v]=u;
}
} void dfs(int fa,int u){
for(int i=heade[u];i;i=nxte[i]){
int v=e[i];
if(v==fa) continue;
dfs(u,v);
f[u]+=f[v];
}
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) p[i]=i; int u,v;
for(int i=;i<n;i++){
scanf("%d%d",&u,&v);
adde(u,v),adde(v,u);
} for(int i=;i<=m;i++){
scanf("%d%d",&u,&v);
addq(u,v),addq(v,u);
} tarjan();
dfs(,); long long ans=;
for(int i=;i<=n;i++)
if(f[i]==) ans++;
else if(!f[i]) ans+=m; printf("%lld\n",ans);
return ;
}
POJ 2374 Fence Obstacle Course
题意:不好描述自己看。
题解:不知道这道题和LCA&RMQ有基本关系。
网上题解都是dp+线段树。
不过我觉得不用线段树,单调队列就可以(怎么单调很好想)。
然而WA了,不理解,拿标称对拍,拍了一大堆数据都没问题,不知道为何WA
欢迎大神帮我查查错。
//6.4 再想了一下单调队列在某些情况下的确有问题,所以还是要线段树,不过为什么对拍都能过,我不知道。。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=5e4+; int a[maxn],b[maxn],anxt[maxn],bnxt[maxn];
int aque[maxn],bque[maxn],at,bt;
ll f[maxn][];
int n,s; int main(){
scanf("%d%d",&n,&s);
for(int i=;i<=n;i++)
scanf("%d%d",&a[i],&b[i]); for(int i=;i<=n;i++){
while(at&&a[aque[at]]>=a[i]) at--;
anxt[i]=aque[at];
aque[++at]=i; while(bt&&b[bque[bt]]<=b[i]) bt--;
bnxt[i]=bque[bt];
bque[++bt]=i;
} memset(f,,sizeof(f));
f[n][]=abs(a[n]-s),f[n][]=abs(b[n]-s); for(int i=n;i>=;i--){
f[anxt[i]][]=min(f[anxt[i]][],f[i][]+abs(a[i]-a[anxt[i]]));
f[anxt[i]][]=min(f[anxt[i]][],f[i][]+abs(a[i]-b[anxt[i]]));
f[bnxt[i]][]=min(f[bnxt[i]][],f[i][]+abs(b[i]-a[bnxt[i]]));
f[bnxt[i]][]=min(f[bnxt[i]][],f[i][]+abs(b[i]-b[bnxt[i]]));
} printf("%lld\n",min(f[][],f[][]));
return ;
}
WA Code
那么我们来总结一下。
感觉LCA常做的有,处理树上路径长度做减法,判断路径是否包含;特殊一点,就是要你统计路径信息,这个就要在求的过程中合并时下功夫;常用的技巧是,DFS+树状数组辅助统计,打标记+树形dp统计。
RMQ貌似还没看到什么比较特殊的。。有一道论文题还可以。。二维RMQ?找个时间填掉。。
【Homework】LCA&RMQ的更多相关文章
- 【BZOJ3626】LCA(树链剖分,Link-Cut Tree)
[BZOJ3626]LCA(树链剖分,Link-Cut Tree) 题面 Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. ...
- 【题解】P4137 Rmq Problem(莫队)
[题解]P4137 Rmq Problem(莫队) 其实这道题根本就不用离散化! 因为显然有\(mex\)值是\(\le 2\times 10^5\)的,所以对于大于\(2\times 10^5\)的 ...
- 【BZOJ-3626】LCA 树链剖分
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1428 Solved: 526[Submit][Status ...
- 【CF52C】Circular RMQ(线段树区间加减,区间最值)
给定一个循环数组a0, a1, a2, …, an-1,现在对他们有两个操作: Inc(le, ri, v):表示区间[le, ri]范围的数值增加v Rmq(le, ri):表示询问区间[le, r ...
- 【模板】LCA
代码如下 #include <bits/stdc++.h> using namespace std; const int maxn=5e5+10; inline int read(){ i ...
- 【LNOI2014】LCA
题面 题解 考察\(dep[\mathrm{LCA}(i, x)]\)的性质,发现它是\(i\)和\(x\)的链交的长度. 那么对每个\(i\)所在的链打一个区间加标记,询问时算一下\(x\)所在的链 ...
- 【BZOJ3626】LCA(树上差分,树链剖分)
题意:给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询问给 ...
- 【模板】Lca倍增法
Codevs 1036 商务旅行 #include<cstdio> #include<cmath> #include<algorithm> using namesp ...
- bzoj3626【LNOI2014】LCA
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1266 Solved: 448 [Submit][Stat ...
随机推荐
- LambdaToSql 发布 兰姆达转换sql
文档目录索引 查询.函数.分组.排序.分页 添加 Insert into 编辑 Update set 删除 Delete 生成实体 内置常用工具类库 文档完善中... 事务处理 Join 连接查询 ...
- 智能合约最佳实践 之 Solidity 编码规范
每一门语言都有其相应的编码规范, Solidity 也一样, 下面官方推荐的规范及我的总结,供大家参考,希望可以帮助大家写出更好规范的智能合约. 命名规范 避免使用 小写的l,大写的I,大写的O 应该 ...
- Dubbo基本特性之泛化调用
Dubbo 是支持泛化调用的,什么是泛化调用呢?泛化调用的好处是什么呢,泛化调用说白一点就是服务消费者并没有服务的接口. 在<Dubbo入门-搭建一个最简单的Demo框架>一文中,我们已完 ...
- django2.0升级日记
1.大量的外键定义需要加on_delete参数 2.'WSGIRequest' object has no attribute 'session',这个问题是因为settings中middleware ...
- Sending forms through JavaScript
https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript As in the ...
- angular2项目如何使用sass
angular/cli支持使用sass 新建工程: 如果是新建一个angular工程采用sass: ng new My_New_Project --style=sass 这样所有样式的地方都将采用sa ...
- C++内存深入理解
转载地址:http://www.cnblogs.com/DylanWind/archive/2009/01/12/1373919.html 前部分原创,转载请注明出处,谢谢! class Base ...
- 5月2日——iOS11定位失效问题
所存在的问题: (1)定位不能正常使用 (2)首次安装APP 时 "是否允许使用定位信息" 系统提示框不显示 iOS定位失效原因: 因为苹果现在增加了一项新的隐私保护功能 NSL ...
- 团队项目第二阶段个人进展——Day5
一.昨天工作总结 冲刺第五天,找到了一个专门的提供后端数据服务的网站:leancloud,并学习了相关操作 二.遇到的问题 对leancloud的数据如何请求和响应不懂 三.今日工作规划 深入学习le ...
- Mego(05) - Mego Tools使用教程
前言 使用过EntityFramework6的朋友应该都知道EF中的PowerTools这个工具可以帮助初学者或者开发人员快速构建一个EF的数据上下文,并且可以很直观的看到实体之间的关系.不过目前升级 ...