hdu_4718_The LCIS on the Tree(树链剖分+线段树合并)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4718
题意:给你一棵树,每个节点有一个值,然后任给树上的两点,问这两点的最长连续递增区间是多少
题解:先树链剖分,然后结合线段树的区间合并来搞,注意的是要记录递增和递减两个状态,因为线段树的区间都是从根到子节点,如果询问从子节点到子节点,那么就是一增一减
#include<cstdio>
#include<algorithm>
#define F(i,a,b) for(int i=a;i<=b;i++)
#define root 1,n,1
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
using namespace std;
const int N=1e5+;
int t,x,y,n,ic=,q,cnt,g[N],ed,nxt[N],v[N],a[N];
inline void adg(int x,int y){v[++ed]=y,nxt[ed]=g[x],g[x]=ed;}
//树链剖分----------------------------
int dep[N],sz[N],fa[N],hs[N],tid[N],top[N],idx,cot[N];
void dfs1(int u,int pre){
dep[u]=dep[pre]+,sz[u]=,fa[u]=pre,hs[u]=;
for(int i=g[u];~i;i=nxt[i]){
dfs1(v[i],u),sz[u]+=sz[v[i]];
if(sz[v[i]]>sz[hs[u]])hs[u]=v[i];
}
}
void dfs2(int u,int tp){
top[u]=tp,tid[u]=++idx,cot[tid[u]]=a[u];
if(hs[u])dfs2(hs[u],tp);
for(int i=g[u];~i;i=nxt[i])if(v[i]!=hs[u])dfs2(v[i],v[i]);
}
//线段树-------------------------------
int Rn[N<<],Ln[N<<],len[N<<],ml[N<<],Rl[N<<];
int Ll[N<<],dml[N<<],dRl[N<<],dLl[N<<]; inline void up(int rt,int li,int ri){
Ln[rt]=Ln[li],Rn[rt]=Rn[ri];
Ll[rt]=Ll[li],Rl[rt]=Rl[ri];
dLl[rt]=dLl[li],dRl[rt]=dRl[ri];
ml[rt]=max(ml[li],ml[ri]);
dml[rt]=max(dml[li],dml[ri]);
if(Rn[li]<Ln[ri]){//左右区间可以合并
ml[rt]=max(ml[rt],Rl[li]+Ll[ri]);
if(Rl[li]==len[li])Ll[rt]=Ll[li]+Ll[ri];
if(Rl[ri]==len[ri])Rl[rt]=Rl[li]+Rl[ri];
}
if(Rn[li]>Ln[ri]){
dml[rt]=max(dml[rt],dRl[li]+dLl[ri]);
if(dRl[li]==len[li])dLl[rt]=dLl[li]+dLl[ri];
if(dRl[ri]==len[ri])dRl[rt]=dRl[li]+dRl[ri];
}
} void build(int l,int r,int rt){
len[rt]=r-l+;
if(l==r){
Ln[rt]=Rn[rt]=cot[l],ml[rt]=Ll[rt]=Rl[rt]=;
dml[rt]=dLl[rt]=dRl[rt]=;
return;
}
int m=(l+r)>>;
build(ls),build(rs),up(rt,rt<<,rt<<|);
}
//将两个区间合并
inline void adt(int li,int ri,int rt){len[rt]=len[li]+len[ri],up(rt,li,ri);} int anson(int l,int r){
int ans=max(dml[l],ml[r]);
if(Ln[l]<Ln[r])return max(ans,dLl[l]+Ll[r]);
return ans;
} int query(int L,int R,int l,int r,int rt){
if(L==l&&R==r)return rt;
int m=(l+r)>>;
if(m>=R)return query(L,R,ls);
else if(m<L)return query(L,R,rs);
else{
int lss=query(L,m,ls),rss=query(m+,R,rs);
adt(lss,rss,++cnt);
return cnt;
}
} int lca(int x,int y){
if(x==y)return ;
cnt=N<<;
int xp=-,yp=-,op;
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]]){
op=query(tid[top[x]],tid[x],root),x=fa[top[x]];
if(xp==-)xp=op;
else adt(op,xp,++cnt),xp=cnt;
}else{
op=query(tid[top[y]],tid[y],root),y=fa[top[y]];
if(yp==-)yp=op;
else adt(op,yp,++cnt),yp=cnt;
}
}
if(dep[x]>=dep[y]){
op=query(tid[y],tid[x],root);
if(xp==-)xp=op;
else adt(op,xp,++cnt),xp=cnt;
}else{
op=query(tid[x],tid[y],root);
if(yp==-)yp=op;
else adt(op,yp,++cnt),yp=cnt;
}
if(xp==-)return ml[yp];
if(yp==-)return dml[xp];
return anson(xp,yp);
} int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
F(i,,N-)g[i]=-;ed=;
F(i,,n)scanf("%d",a+i);
F(i,,n)scanf("%d",&x),adg(x,i);
dfs1(,),idx=,dfs2(,),build(root);
scanf("%d",&q);
printf("Case #%d:\n",ic++);
while(q--)scanf("%d%d",&x,&y),printf("%d\n",lca(x,y));
if(t)puts("");
}
}
hdu_4718_The LCIS on the Tree(树链剖分+线段树合并)的更多相关文章
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- POJ3237 Tree 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...
- 【CF725G】Messages on a Tree 树链剖分+线段树
[CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...
- Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
- Water Tree CodeForces 343D 树链剖分+线段树
Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- B20J_3231_[SDOI2014]旅行_树链剖分+线段树
B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
随机推荐
- foreach 循环的应用传值
$arr=array(1,5,8,8,9);foreach ($arr as $key => $value) { //这里可以一边改外面$arr的值一边下一步循环 $value=++$value ...
- Linux文件系统简介及常用命令
在linux系统中一切皆是文件,下面简要总结了一下linux文件系统中分区类型.文件系统类型以及常用命令. 一.分区类型1.主分区:最多只能有四个2.扩展分区:只能有一个,也可以看做是主分区的一种.即 ...
- python操作----Memcached
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.Memcached ...
- 实验吧Web-PHP大法
笔记 字符串比对解析,与大小写无关. eregi()函数 语法: eregi(string pattern, string string, array [regs]); 返回值: 整数/数组 特点:P ...
- 2016年团体程序设计天梯赛-决赛 L1-8. Left-pad(20)
根据新浪微博上的消息,有一位开发者不满NPM(Node Package Manager)的做法,收回了自己的开源代码,其中包括一个叫left-pad的模块,就是这个模块把javascript里面的Re ...
- hdu 1407 测试你是否和LTC水平一样高
Description 大家提到LTC都佩服的不行,不过,如果竞赛只有这一个题目,我敢保证你和他绝对在一个水平线上! 你的任务是: 计算方程x^2+y^2+z^2= num的一个正整数解. Inpu ...
- SpringMVC 的重定向时,参数非法问题
在重定向时,携带的参数出现非法 /shopping/editShippingAddressCart?cs=0eaa49d6-9c6e-4d02-85d0-40c3c7939207|ef9d80b1-7 ...
- NFS挂载故障卡死的问题
NFS挂载故障卡死的问题 默认是硬的,改成软的.比如:mount -t nfs -o rw,vers=4,noacl,nocto,noatime,nodiratime,rsize=131072,wsi ...
- 【strtok()】——分割字符串
对字符串进行分割: 在使用前需要先初始化例如: char * p=strtok(Str," ");/*初始化以" "(以空格字符来分割字符串),即把" ...
- 自定义函数动态执行SQL语句
Oracle 动态SQL有两种写法:用 DBMS_SQL 或 execute immediate,建议使用后者. DDL 和 DML Sql代码 收藏代码 /*** DDL ***/ begin EX ...