【BZOJ4358】permu

原创 2016年04月24日 08:54:03

Description

给出一个长度为n的排列P(P1,P2,…Pn),以及m个询问。每次询问某个区间[l,r]中,最长的值域
连续段长度。
Input

第一行两个整数n,m。
接下来一行n个整数,描述P。
接下来m行,每行两个整数l,r,描述一组询问。
Output

对于每组询问,输出一行一个整数,描述答案。
Sample Input

8 3

3 1 7 2 5 8 6 4

1 4

5 8

1 7
Sample Output

3

3

4
HINT

对于询问[1,4],P2,P4,P1组成最长的值域连续段[1,3];

对于询问[5,8],P8,P5,P7组成最长的值域连续段[4,6];

对于询问[1,7],P5,P7,P3,P6组成最长的值域连续段[5,8]。

1<=n,m<=50000

Source

By sumix173

跟Kangroo一样..改成把给定的n个排列数排序然后插入就行了
现在发现那种[L,R]->(L,R)的方式就是KDtree处理一系列使用树套树的序列问题的通法,甚至可以使用DFS序扩展到树上.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 50010
#define Dnum 2
#define GET (ch>='0'&&ch<='9')
using namespace std;
inline void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
int n,m,root;
bool cmp_d;
int id[MAXN];
struct KDtree
{
    int ch[2],f,d[Dnum],minn[Dnum],maxn[Dnum],maxv[Dnum],maxt[Dnum],mint;
    inline void init()  {   for (int i=0;i<Dnum;++i)    minn[i]=maxn[i]=d[i],maxv[i]=maxt[i]=0; }
    inline bool operator < (const KDtree& a)const   {   return d[cmp_d]<a.d[cmp_d]; }
}tree[MAXN];
struct Query
{
    int p,id;
    inline bool operator < (const Query& a)const    {   return p<a.p;   }
}q[MAXN];
inline void add(int rt,int x,int y)
{
    if (~x)
    {
        if (~tree[rt].mint)    tree[rt].maxv[0]=max(tree[rt].maxv[0],x-tree[rt].maxt[0]-1);
        else    tree[rt].mint=x;
        tree[rt].maxv[1]=max(tree[rt].maxv[1],x-tree[rt].maxt[1]-1);
        tree[rt].maxt[0]=tree[rt].maxt[1]=y;
    }
}
inline void push_up(int rt)
{
    for (int x=0,i=0;i<2;++i)
        if ((x=tree[rt].ch[i]))
            for (int j=0;j<Dnum;++j)
                tree[rt].minn[j]=min(tree[rt].minn[j],tree[x].minn[j]),
                tree[rt].maxn[j]=max(tree[rt].maxn[j],tree[x].maxn[j]);
}
inline void push_down(int rt)
{
    int x=tree[rt].mint,y=tree[rt].maxt[0];
    for (int i=0,j=0;i<2;++i)   if ((j=tree[rt].ch[i])) add(j,x,y);
    tree[rt].mint=-1;
}
int rebuild(int l=1,int r=m,bool d=0,int f=0)
{
    cmp_d=d;int mid=(l+r)>>1;nth_element(tree+l,tree+mid,tree+r+1);
    id[tree[mid].f]=mid;tree[mid].f=f;tree[mid].init();
    if (l!=mid) tree[mid].ch[0]=rebuild(l,mid-1,d^1,mid);
    if (r!=mid) tree[mid].ch[1]=rebuild(mid+1,r,d^1,mid);
    return push_up(mid),mid;
}
inline int check(int x1,int y1,int x2,int y2,int x,int y)
{
    int ret=0;
    ret+=(x1<=x&&y1>=y);ret+=(x1<=x&&y2>=y);ret+=(x2<=x&&y1>=y);ret+=(x2<=x&&y2>=y);
    return ret?(ret==4?1:2):0;
}
void modify(int rt,int x,int y,int id)
{
    int flag=check(tree[rt].minn[0],tree[rt].minn[1],tree[rt].maxn[0],tree[rt].maxn[1],x,y);
    if (!flag)  {   add(rt,id,id);return;   }
    if (flag==1)    return;
    if (tree[rt].d[0]>x||tree[rt].d[1]<y)   tree[rt].maxv[1]=max(tree[rt].maxv[1],id-tree[rt].maxt[1]-1),tree[rt].maxt[1]=id;
    push_down(rt);
    for (int i=0;i<2;++i)   if (tree[rt].ch[i]) modify(tree[rt].ch[i],x,y,id);
}
void update(int rt,int x)
{
    push_down(rt);
    tree[rt].maxv[1]=max(tree[rt].maxv[1],n-tree[rt].maxt[1]);
    tree[rt].maxv[1]=max(tree[rt].maxv[1],x);
    tree[rt].maxv[0]=max(tree[rt].maxv[0],x);
    tree[rt].maxv[1]=max(tree[rt].maxv[1],tree[rt].maxv[0]);
    for (int i=0;i<2;++i)   if (tree[rt].ch[i]) update(tree[rt].ch[i],tree[rt].maxv[0]);
}
int main()
{
    in(n);in(m);
    for (int i=1;i<=n;++i)  in(q[i].p),q[i].id=i;
    for (int i=1;i<=m;++i)  in(tree[i].d[0]),in(tree[i].d[1]),tree[i].f=i;
    root=rebuild();sort(q+1,q+n+1);
    for (int i=1;i<=n;++i)  modify(root,q[i].id,q[i].id,i);
    update(root,0);
    for (int i=1;i<=m;++i)  printf("%d\n",tree[id[i]].maxv[1]);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/CreationAugust/article/details/51231980

bzoj 4358: permu (莫队+栈||KD-tree||莫队+线段树)

题目描述传送门题目大意:给出一个长度为n的排列P(P1,P2,…Pn),以及m个询问。每次询问某个区间[l,r]中,最长的值域 连续段长度。题解1:莫队+线段树用权值线段树维护区间的连续最大长度,左...
  • clover_hxy
  • clover_hxy
  • 2017-03-31 19:28:03
  • 619

BZOJ 4358 permu

http://www.elijahqi.win/2017/07/07/bzoj-4358-permu/ Description 给出一个长度为n的排列P(P1,P2,…Pn),以及m个询问。每次询...
  • elijahqi
  • elijahqi
  • 2018-01-13 19:43:49
  • 34

bzoj4358 permu(莫队+线段树||莫队+并查集+分块||K-D tree)

很久以前的坑=,= 题意:给你一个排列序列,每次询问问l,r区间内最长的值域连续段长度。范围50000,长得就像莫队-,-。怎么转移呢,首先有一个比较明显的做法,用数值建一棵线段树,维护最大子段和。这...
  • Icefox_zhx
  • Icefox_zhx
  • 2017-08-03 11:55:50
  • 238

4358: permu|K-Dtree

几天之前写了个莫队+线段树T的飞起。。(据说卡常数可以卡过去。。 然后可以KD树做,标记比较难处理。 ymClairs的KD树神之标记http://www.cnblogs.com/clrs97/p...
  • ws_yzy
  • ws_yzy
  • 2016-03-14 08:53:47
  • 386

bzoj4358 perm

启发式合并,思路好题
  • AaronGZK
  • AaronGZK
  • 2016-03-10 09:32:35
  • 1514

[ KD-tree ] BZOJ4358

题解 #include using namespace std; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; ...
  • gjghfd
  • gjghfd
  • 2018-01-19 15:10:35
  • 61

[BZOJ4605]崂山白花蛇草水(主席树套kd-tree)

题意:两种操作,在二维平面插入一个点及其权值,查询矩形区间第k大,强制在线。 之前考试考过一个矩形区间第k大的题。。当时想了各种树套树套树,算了算复杂度都没有暴力快。。后来憋了个kd-tree套主席...
  • u011542204
  • u011542204
  • 2016-05-24 22:55:18
  • 1554

HDU 4358 Boring counting 莫队算法

题目大意: 就是现在给出一个有N个结点的树(N 大致思路: 第一次写莫队算法..... 对于静态的满足能在O(1)的时间把[L, R]的答案转移到[L, R + 1], [L - 1...
  • u013738743
  • u013738743
  • 2015-08-03 22:25:40
  • 837

kd-tree讲解 & bzoj 2648 & 2716 & 3053 题解

【KD-TREE介绍】在SYC1999大神的“蛊惑”下,我开始接触这种算法。 首先,大概的概念可以去百度百科。具体实现,我是看RZZ的代码长大的。 我们可以想象在平面上有N个点。首先,按横坐标排序...
  • u013724185
  • u013724185
  • 2014-06-24 21:14:49
  • 4277

【BZOJ4358】permu

Description给出一个长度为n的排列P(P1,P2,…Pn),以及m个询问。每次询问某个区间[l,r]中,最长的值域 连续段长度。 Input第一行两个整数n,m。 接下来一行n个整数,...
  • CreationAugust
  • CreationAugust
  • 2016-04-24 08:54:03
  • 843
收藏助手
不良信息举报
您举报文章:【BZOJ4358】permu
举报原因:
原因补充:

(最多只允许输入30个字)