【NOIP2017模拟8.8】Trip

Description

多年之后,worldwideD厌倦竞争,隐居山林。
       他的家乡开始发展起了旅游业,在一条很长的主干道上,有N个旅游景点,按顺序编号为1到N。根据游客们网上的评分,第i个景点有一个评估值a[i],为了区分开不同的景点,评估值是两两不同的。
       今天有M组游客前来旅游,第i组游客选择遍历景点Li到景点Ri这一段路。他们搜到Li到Ri的所有评估值,如果对于景点j(Li≤j≤Ri),不存在景点x(Li≤x<j)满足a[x]>a[j]或不存在景点y(j<y≤Ri)满足a[y]>a[j],那么他们会进入景点j。
       现在worldwideD想知道,每组游客会去多少个景点。

Input

第一行两个整数N,M,意义见题面。
接下来一行N个整数,第i个是a[i],意义见题面。
接下来M行,第i行两个整数Li,Ri,意义见题目。

Output

M行,第i行表示第i组游客去的景点个数。

Sample Input

6 4
3 1 7 4 5 2
1 5
2 5
2 6
4 6

Sample Output

3
3
4
3

Data Constraint

30%:N,M≤5,000
60%:N,M≤100,000
100%:N,M≤1,000,000   0≤|a[i]|≤1,000,000,000  1≤Li≤Ri≤N

Hint

第一组游客选择路段的景点评估值序列为[3,1,7,4,5],其中3,7,5满足条件
第二组游客选择路段的景点评估值序列为[1,7,4,5],其中1,7,5满足条件
第三组游客选择路段的景点评估值序列为[1,7,4,5,2],其中3,7,5,2满足条件
第四组游客选择路段的景点评估值序列为[4,5,2],其中4,5,2满足条件
本题数据规模较大,请注意您的常数造成的影响。
在这里给出一种输入输出优化的模板,在主程序中直接调用read()即可读入一个整数,调用write(x)可以把一个int变量x输出并换行。
int read()
{
       int x=0,sig=1;
       char c;
       for (c=getchar();c<‘0‘ || c>‘9‘;c=getchar()) if (c==‘-‘) sig=-1;
       for (;c>=‘0‘ && c<=‘9‘;c=getchar()) x=x*10+c-48;
       return x*sig;
}
void write(int x)
{
       if (!x) putchar(‘0‘);else
       {
              char s[10];
              int i,j=0;
              for (;x>0;x/=10) s[j++]=x%10;
              for (i=j-1;i>=0;i--) putchar(s[i]+48);
       }
       putchar(‘\n‘);
}

考虑30分的可以拿个单调栈向左扫一遍向右扫一遍再将个数加起来再减去1即可。

这道题是要求我们判断这个景点的评估值在给定的子区间里是否有比它大值存在,如果一边没有大于它的存在,则它就是旅客会前往的景点。

既需要位置关系又需要大小关系,我们考虑大根笛卡尔树。

笛卡尔树是一种同时满足二叉搜索树和堆的性质的数据结构。

它的中序遍历的序列为原数组序列。

树中节点的值大于其左右子节点的值。

建树很简单, 用个单调栈O(n)即可建好。我们很容易发现一些性质:

1.对于一个询问L,R它的答案只会出现在笛卡尔树的路径上。

2.L,R的LCA中,从L到LCA路径上,有一个点是其父亲的左孩子答案就加一,R到LCA上,有一个点是其父亲的右孩子答案就加一。

我们知道笛卡尔树上一个点A是其父亲B的左孩子表明A在它父亲B的左边,且权值小于父亲B,对于LLCA路径(也就是区间L-LCA)中而言这意味着A的左边没有比它大的点(如果有,那么A应该会在比它大的那个点C的右边),于是就对答案有1的贡献,虽然右边有比它大的点(父亲B);对于RLCA路径(也就是区间LCA-R)中则相反。这就很好的符合题目的性质,我们就可以用笛卡尔树解决这道题了。

我们就可以用tarjan求出LCA,然后预处理下每个点到根节点的路径上有多少个点是其父亲的左孩子和右孩子,然后计算出答案即可。时间复杂度 O(NαN)

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #define N 3000002
  5 using namespace std;
  6 int n,m,t,zhan[N],len,num,ans[N],f[N],u,v,head[N],root,visit[N];
  7 struct data1{
  8     int l,r,p,v,lnum,rnum;
  9     void init(){
 10         l=0,r=0,p=0,v=0,lnum=0,rnum=0;
 11     }
 12 }tree[N];
 13 struct data2{
 14     int next,to,sign;
 15 }line[N];
 16 int read()
 17 {
 18        int x=0,sig=1;
 19        char c;
 20        for (c=getchar();c<‘0‘ || c>‘9‘;c=getchar()) if (c==‘-‘) sig=-1;
 21        for (;c>=‘0‘ && c<=‘9‘;c=getchar()) x=x*10+c-48;
 22        return x*sig;
 23 }
 24 void write(int x)
 25 {
 26        if (!x) putchar(‘0‘);else
 27        {
 28               char s[10];
 29               int i,j=0;
 30               for (;x>0;x/=10) s[j++]=x%10;
 31               for (i=j-1;i>=0;i--) putchar(s[i]+48);
 32        }
 33        putchar(‘\n‘);
 34 }
 35 void add(int u,int v){
 36     num++;
 37     line[num].next=head[u];
 38     line[num].to=v;
 39     line[num].sign=num;
 40     head[u]=num;
 41     num++;
 42     line[num].next=head[v];
 43     line[num].to=u;
 44     line[num].sign=num;
 45     head[v]=num;
 46 }
 47 int build(){     //建笛卡尔树
 48     len=1;
 49     zhan[1]=1;
 50     for (int i=2;i<=n;i++){
 51         while ((len>0)&&(tree[zhan[len]].v<tree[i].v)) len--;
 52         if (len){
 53             tree[i].p=zhan[len];
 54             tree[tree[zhan[len]].r].p=i;
 55             tree[i].l=tree[zhan[len]].r;
 56             tree[zhan[len]].r=i;
 57         }
 58         else {
 59             tree[zhan[1]].p=i;
 60             tree[i].l=zhan[1];
 61         }
 62         zhan[++len]=i;
 63     }
 64     return zhan[1];
 65 }
 66 int find(int x){
 67     if (f[x]==x) return x;
 68     f[x]=find(f[x]);
 69     return f[x];
 70 }
 71 void tarjan(int x,int ln,int rn){   //Tarjan求LCA
 72     f[x]=x;
 73     visit[x]=1;
 74     tree[x].lnum=ln;
 75     tree[x].rnum=rn;
 76     if (tree[x].l) {
 77         tarjan(tree[x].l,ln+1,rn);
 78         f[tree[x].l]=x;
 79     }
 80     if (tree[x].r) {
 81         tarjan(tree[x].r,ln,rn+1);
 82         f[tree[x].r]=x;
 83     }
 84     int v=0,e=0;
 85     for (int i=head[x];i!=0;i=line[i].next){
 86         v=line[i].to;
 87         if (visit[v]){e=find(v);
 88         if (line[i].sign&1) ans[(line[i].sign+1)/2]=tree[x].lnum-tree[e].lnum+tree[v].rnum-tree[e].rnum+1;
 89         else ans[line[i].sign/2]=tree[v].lnum-tree[e].lnum+tree[x].rnum-tree[e].rnum+1;
 90         }
 91     }
 92 }
 93 int main(){
 94     freopen("trip.in","r",stdin);
 95     freopen("trip.out","w",stdout);
 96     memset(visit,0,sizeof(visit));
 97     n=read();
 98     m=read();
 99     for (int i=1;i<=n;i++){
100         tree[i].init();
101         tree[i].v=read();
102     }
103     root=build();
104     num=0;
105     for (int i=1;i<=m;i++){
106         u=read();
107         v=read();
108         add(u,v);
109     }
110     tarjan(root,0,0);
111     for (int i=1;i<=m;i++)
112      write(ans[i]);
113     return 0;
114 }

神奇的代码

联想很重要

时间: 2024-12-28 15:41:40

【NOIP2017模拟8.8】Trip的相关文章

JZOJ.5281【NOIP2017模拟8.15】钦点

Description Input Output Sample Input 4 4 2 a a b b a a b b c c d d c c d d 1 1 3 3 2 2 3 1 1 3 2 2 Sample Output d d c c  d d c c  b b a a  b b a a  Data Constraint 本题时限4s. 很明显这是一道模拟题,朴素算法O(nmq)看似过得去,实际上字符串的操作是很慢的,同样对字符串赋值10w次比对数组元素赋值10w次要慢3倍以上. 实际上

暑假第二次考试 冲刺Noip2017模拟赛2 解题报告——五十岚芒果酱

题1 牛跑步(running) [题目描述] 新牛到部队,CG 要求它们每天早上搞晨跑,从 A 农场跑到 B 农场.从 A 农场到 B 农场中有 n-2 个路口,分别标上号,A 农场为 1 号,B 农场为 n 号,路口分别为 2...n-1 号,从 A 农场到 B 农场有很多条路径可以到达,而 CG 发现有的路口是必须经过的,即每条路径都经过的路口,CG 要把它们记录下来,这样 CG 就可以先到那个路口,观察新牛们有没有偷懒,而你的任务就是找出所有必经路口. [输入格式] 第一行两个用空格隔开的

冲刺Noip2017模拟赛8 解题报告——五十岚芒果酱

1.鼎纹 [问题描述] 据说鼎纹的 种制造 式是 铜模印出来的,这是我国古代劳动 智慧 的结晶.铜模印过的地 ,会留下深深的印记,经过时间的炼化,洗 练成历史的遗存. 聪明的古代劳动人民拥有一个 a 行 b 列的铜模,每个位置要么是 0(代表 这个点是平的),要么是 1(代表这个点是凸起的).他们想造 个 n 行 m 列 的鼎 ,其中每个位置也都是 0 或 1,表示经过若干 次印后,每个位置的结果. 有一些要求.铜模是不能旋转和翻转的:在印的过程当中,铜模的凸起不 能出现在鼎面的外面(平的部分是

冲刺Noip2017模拟赛7 解题报告——五十岚芒果酱

1.二叉树(binary) 1.二叉树 (binary.cpp/c/pas) [问题描述] 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值: (3)左.右子树也分别为二叉排序树: (4)没有键值相等的结点. 完全二叉树:只有最下面的两层结点度能够小于2,并且最下面一层的结点 都集中在该层最左边的若干位置的二叉树. 图1中,(a)和(b)是完全二叉树,(c)和(

JZOJ.5331【NOIP2017模拟8.23】壕游戏

Description Input Output Sample Input 6 8 2 2 4 5  1 2 4 0 2 1 3 5 0 2 3 4 1 5 1 2 5 1 0 1 4 6 4 2 2 5 6 0 4 2 1 5 5 9 2 2 6 4 5 2 Sample Output 16 Data Constraint Hint 类似于一种可撤销的贪心,不难想到这是费用流的模型. 考虑到我们实际会用到的边比实际的边少很多,我们可以动态建边,以减少空间的使用,即当流过了一条边之后再建立第二次

JZOJ.5274【NOIP2017模拟8.14】数组

Description Input Output Sample Input 输入样例1: 3 2 7 5 4 2 输入样例2: 5 3 1 5 4 3 5 5 Sample Output 输出样例1: 999999732 输出样例2: 0 Data Constraint 这个题要求乘积最小,显然我们希望乘积是负数是最好的,然后就是让这个负数的绝对值尽可能的大. 对于一堆数相乘,绝对值最小的对这个结果影响是最大的,所以我们就每次让绝对值最小的,如果是正数就加上x,负数就减去x,用个优先队列维护绝对

Codeforces 703B (模拟) Mishka and trip

题目:这里 题意:n个城市,每个城市有个魅力值vi,首先,有n条路将这n个城市连成一个环,1号城市连2号城市,2号连3号****n号连1号城市,每条路的魅力值是其连接的两个城市 的魅力值的乘积,这n个城市其中还有k个是特殊城市,每个特殊城市和任意一条城市都有一条路连接,看题目下面的图,保证每两个城市之间最多只有一条路,问所有路的 魅力值之和是多少? 首先是连接成环的路线魅力值,很好算,然后每个特殊城市的路线,先求出所有城市的魅力值之和sum,依次求特殊城市的时候用sum减去这个特殊城市本身以及两

【NOIP2017模拟8.7】外星人的路径

Description 有一个外星人控制了你的大脑.一开始你处于原点(0,0).外星人有一个由(R,U,D,L)组成的长度为M 的操作序列,分别代表(右,上,下,左).平面上有N 个关键点,每当外星人给出一个操作,你需要在这个方向上找到最近的一个关键点,并走到那个点上.保证输入数据合法.上图为第三个样例的图示. Input 第一行两个整数N,M.接下来N 行,每行两个整数xi,yi,代表第i 个点的坐标.接下来一行,一个长度为M 的字符串,代表操作序列. Output 一行两个整数,代表最终你所

【NOIP2017模拟8.5】序列问题

Description Input 输入文件名为seq.in.首先输入n.接下来输入n个数,描述序列 A. Output 输出文件名为seq.out.输出一行一个整数代表答案. Sample Input 7 0 35 40 45 56 65 94 Sample Output 66636 Data Constraint 对于30%的数据,n<=5000对于60%的数据,n<=50000对于100%的数据,n<=500000,0<=A[i]<=10^9 ST加暴力枚举区间显然过不