Vijos1448题解---线段树+括号法

描述

校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
K=1,K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同
K=2,读入l,r表示询问l~r之间能见到多少种树(l,r>0)

输入格式

第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作

输出格式

对于每个k=2输出一个答案

样例输入

5 4

1 1 3

2 2 5

1 2 4

2 3 5

样例输出

1

2

普通的暴力算法,植树的时间为O(n),查询的时间也为O(n),所以总体的时间复杂度为O(nm)。

这里介绍一种独特的想法---括号法。

在植树区间的左端点放一个左括号“(”,右端点放一个右括号“)”,使得植树时间为O(1)。

显而易见,查询的结果为右端点左边“(”的个数减去左端点左边“)”的个数,时间为O(n)。

2至5之间有2-1=1种树。

3至5之间有2-0=2种树。

为了进一步优化时间复杂度,我们使用线段树维护左右括号的数量,使时间降到log级。

献上代码:

 1 #include <cstdio>
 2 int n,m;
 3 struct node
 4 {
 5     int x,y;
 6     int a[3];//a[1]表示左括号的数量,a[2]表示右括号的数量。
 7 }t[300002];
 8 void init(int k,int l,int r)//初始化。
 9 {
10     t[k].x=l;
11     t[k].y=r;
12     if(l==r)return;
13     int mid=(l+r)/2;
14     init(2*k,l,mid);
15     init(2*k+1,mid+1,r);
16 }
17 void build(int k,int l,int op)
18 {
19     if(t[k].x<=l&&l<=t[k].y)//若在当前节点的范围内,括号数量加1。
20         t[k].a[op]++;
21     if(t[k].x==t[k].y)return;
22     int mid=(t[k].x+t[k].y)/2;
23     if(l<=mid)build(2*k,l,op);//查询左儿子。
24     if(l>=mid+1)build(2*k+1,l,op);//查询右儿子。
25 }
26 int find(int k,int l,int r,int op)//查找l到r内括号的个数。
27 {
28     int ans=0;
29     if(l<=t[k].x&&t[k].y<=r)return t[k].a[op];
30     int mid=(t[k].x+t[k].y)/2;
31     if(l<=mid)ans+=find(2*k,l,r,op);
32     if(r>=mid+1)ans+=find(2*k+1,l,r,op);
33     return ans;
34 }
35 int main()
36 {
37     int k,l,r,ans1,ans2;
38     scanf("%d%d",&n,&m);
39     init(1,1,n);
40     for(int i=1;i<=m;i++)
41     {
42         scanf("%d%d%d",&k,&l,&r);
43         if(k==1)
44         {
45             build(1,l,1);
46             build(1,r,2);
47         }
48         if(k==2)
49         {
50             ans1=ans2=0;
51             ans1=find(1,1,r,1);
52             if(l-1>=1)ans2=find(1,1,l-1,2);
53             printf("%d\n",ans1-ans2);
54         }
55     }
56     return 0;
57 }
时间: 2024-08-29 07:08:47

Vijos1448题解---线段树+括号法的相关文章

POJ2182题解——线段树

POJ2182题解——线段树 2019-12-20 by juruoOIer 1.线段树简介(来源:百度百科) 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN).而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩. 2.线段树实际应用 上面的都是些基本的线段树结构,但只有这些并不能做什么,就好比一个程序有

理想乡题解 (线段树优化dp)

题面 思路概述 首先,不难想到本题可以用动态规划来解,这里就省略是如何想到动态规划的了. 转移方程 f[i]=min(f[j]+1)(max(i-m,0)<=j<i 且j符合士兵限定) 注意要用 max(i-m,0)以防止越界 我们先用两个数组sl,sa分别统计1~i个士兵中有多少个Lencer和Archer 然后在max(i-m,0)中寻找符合条件的j (1).两种士兵相差不超过k. 这个好说abs((sl[i]-sl[j])-(sa[i]-sa[j]))<=k 不要忘了第二种情况!!

[题解]线段树专题测试2017.1.21

很单纯的一道线段树题.稍微改一下pushDown()就行了. Code(线段树模板竟然没超100行) 1 #include<iostream> 2 #include<sstream> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<cctype> 8 #include<queue> 9

codedecision P1112 区间连续段 题解 线段树

题目描述:https://www.cnblogs.com/problems/p/P1112.html 题目链接:http://codedecision.com/problem/1112 线段树区间操作,每一个线段对应的点包含三个信息: \(l\):表示这个区间最左边的点的数值: \(r\):表示这个区间最右边的点的数值: \(cnt\):表示这个区间有多少个数值段. 合并的时候: 根节点的 \(l\) 值等于左儿子节点的 \(l\) 值: 根节点的 \(r\) 值等于右儿子节点的 \(r\) 值

codeforces 380C 线段树括号匹配

Sereja and Brackets Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Description Sereja has a bracket sequence s1,?s2,?...,?sn, or, in other words, a string s of length n, consisting of characters "(&quo

zoj 3573 Under Attack(线段树 标记法 最大覆盖数)

Under Attack Time Limit:  10 Seconds      Memory Limit:  65536 KB Doctor serves at a military air force base. One day, the enemy launch a sudden attack and the base is under heavy fire. The fighters in the airport must take off to intercept enemy bom

HDU 1754 I Hate It 线段树

I Hate It Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师有时候需要更新某位同学的成绩. Input 本题目包含多组测试,请处理到文件结束.在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目.学生ID编号分别从1编到N.第二行包

HDU 1166 敌兵布阵 线段树

敌兵布阵 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视.中央情

【bzoj4276】[ONTAK2015]Bajtman i Okr?g?y Robin 线段树优化建图+费用流

题目描述 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢走c[i]元.作为保安,你在每一段长度为1的时间内最多只能制止一个强盗,那么你最多可以挽回多少损失呢? 输入 第一行包含一个正整数n(1<=n<=5000),表示强盗的个数. 接下来n行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<b[i]<=5000,1<=c[i]