2018-08-14 线段树

  • A  -- I Hate It

  • Description

很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。

  • Input

本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。
当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。

  • Output

对于每一次询问操作,在一行里面输出最高成绩。

  • Sample Input

5

6 1 2 3 4 5

Q 1 5

U 3 6

Q 3 4

Q 4 5

U 2 9

Q 1 5

  • Sample Output

5

6

5

9

  • 题目理解

这道题只是进行单点更改,区间查询;只需要在插入的过程进行dfs调用然后在函数退出的时候向上更新维护最大值即可

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
int n,m;
int a[maxn];
struct node{int l,r,maxnum;}//结点需要维护左右端点信息
tree[maxn<<2];
char ch[2];
void build(int k,int l,int r)
{
	tree[k].l=l;tree[k].r=r;
	if(l==r)
	{
		tree[k].maxnum=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);build(k<<1|1,mid+1,r);
	tree[k].maxnum=max(tree[k<<1].maxnum,tree[k<<1|1].maxnum);
}
void change(int k,int d,int x)//单点
{
	if(tree[k].l==tree[k].r && tree[k].r==d)
	{
		tree[k].maxnum=x;
		return;
	}
	int mid=(tree[k].l+tree[k].r)/2;
	if(d>=tree[k].l && d<=mid)
		change(k<<1,d,x);
	else
		change(k<<1|1,d,x);
	tree[k].maxnum=max(tree[k<<1].maxnum,tree[k<<1|1].maxnum);
}

int query(int k,int l,int r)//区间查询
{
	int maxnum;
	if(tree[k].l==l && tree[k].r==r)
		return tree[k].maxnum;
	int mid=(tree[k].l+tree[k].r)>>1;
	if(r<=mid)
		maxnum=query(k<<1,l,r);
	else
	if(l>=mid+1)
		maxnum=query(k<<1|1,l,r);
	else
		maxnum=max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
	return maxnum;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=1;i<=n;i++)
		   scanf("%d",&a[i]);
	    memset(tree,0,sizeof(tree));
	    build(1,1,n);
		int d,x;
	    for(int i=1;i<=m;i++)
	    {
		    scanf("%s%d%d",ch,&d,&x);
		    if(ch[0]=='Q')
			   printf("%d\n",query(1,d,x));
		    else
			   change(1,d,x);
	     }
	}
	return 0;
}

 

  • C  -- Fast Arrangement

  • Description

Chinese always have the railway tickets problem because of its' huge amount of passangers and stations. Now goverment need you to develop a new tickets query system.
One train can just take k passangers. And each passanger can just buy one ticket from station a to station b. Each train cannot take more passangers any time. The one who buy the ticket earlier which can be sold will always get the ticket.

  • Input

The input contains servel test cases. The first line is the case number. In each test case:
The first line contains just one number k( 1 ≤ k ≤ 1000 ) and Q( 1 ≤ Q ≤ 100000 )
The following lines, each line contains two integers a and b, ( 1 ≤ a < b ≤ 1000000 ), indicate a query.
Huge Input, scanf recommanded.

  • Output

For each test case, output three lines:
Output the case number in the first line.
If the ith query can be satisfied, output i. i starting from 1. output an blank-space after each number.
Output a blank line after each test case.

  • Sample Input

1

3 6

1 6

1 6

3 4

1 5

1 2

2 4

  • Sample Output

Case 1:

1 2 3 5

  • 题目理解

区间插入和区间查询操作,每次查询区间相当于\small [l,r)里的元素最大值进行查询,如果大于最多乘坐人数就应该拒绝这次购票,如果没有就应该将该\small [l,r)区间插入,即\small [l,r)内元素进行自增相应的最大值也应该增加1.这里由于是区间插入不能对区间里的每个元素都进行修改代价太大所以需要用到\small lazy标志,当大区间满足要求的时候不需要将后面的小区间全部更新,而是当使用到它们的时候将\small lazy值传递下去,在退栈的时候也要进行向上更新,因为更大的区间在上次修改最值过程没有任何操作,所以需要向上更新保证数据的正确。注意因为当\small lazy传递的过程中可能原来的\small lazy已经存在值了所以应该是在原来的基础上增加而不是直接赋值,当进行向下\small lazy值的传递的时候需要将当前\small lazy值清零。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000005;
int ans[maxn];
struct node
{
    int l,r,m,lazy;
}node[maxn<<2];
void build(int l,int r,int k)    //  线段树的建立;
{
    node[k].l=l;
    node[k].r=r;
    node[k].m=0;
    node[k].lazy=0;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
}
void PushUp(int k)
{
    node[k].m=max(node[k<<1].m,node[k<<1|1].m);
}
void PushDown(int k)
{
    node[k<<1].lazy+=node[k].lazy;
    node[k<<1|1].lazy+=node[k].lazy;
    node[k<<1].m+=node[k].lazy;
    node[k<<1|1].m+=node[k].lazy;
    node[k].lazy=0;
}

void Insert(int l,int r,int k)
{
    if(node[k].l==l&&node[k].r==r)//整个区间被包含那么最大值增加1
    {
        node[k].m+=1;
        node[k].lazy+=1;
        return;
    }
    if(node[k].lazy) PushDown(k);//更新子节点,保证子节点的值在访问前正确
    int mid=(node[k].r+node[k].l)>>1;
    if(l>mid) Insert(l,r,k<<1|1);
    else if(r<=mid) Insert(l,r,k<<1);
    else{
        Insert(l,mid,k<<1);
        Insert(mid+1,r,k<<1|1);
    }
    PushUp(k);
}
int query(int l,int r,int k)
{
    if(node[k].l==l&&node[k].r==r){
        return node[k].m;
    }
    if(node[k].lazy) PushDown(k);
    int mid=(node[k].r+node[k].l)>>1;
    if(l>mid) return query(l,r,k<<1|1);
    else if(r<=mid) return query(l,r,k<<1);
    else{
        return max(query(l,mid,k<<1),query(mid+1,r,k<<1|1));
    }
}
int main()
{
    int t,ed,k,m,l,r;
    scanf("%d",&t);
    for(int cas=1;cas<=t;++cas){
        ed=0;
        memset(ans,0,sizeof(ans));
        scanf("%d%d",&k,&m);
        build(1,1000000,1);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&l,&r);
            r--;
            if(query(l,r,1)<k){
                ans[ed++]=i;
                Insert(l,r,1);
            }
        }
        printf("Case %d:\n",cas);
        for(int i=0;i<ed;i++)
            printf("%d ",ans[i]);
        printf("\n\n");
    }
    return 0;
}

 

  • D  -- Can you find it?

  • Description

In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.
 

Now Pudge wants to do some operations on the hook.
Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:
For each cupreous stick, the value is 1.
For each silver stick, the value is 2.
For each golden stick, the value is 3.
Pudge wants to know the total value of the hook after performing the operations.
You may consider the original hook is made up of cupreous sticks.

  • Input

The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.

  • Output

For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.

  • Sample Input

1

10

2

1 5 2

5 9 3

  • Sample Output

Case 1: The total value of the hook is 24.

  • 题目理解

这道题和上一道题的思路基本上是一样的,向下传递\small lazy标志以及向上进行值的更新。因为大区间在退栈的时候已经向上更新了所以大区间的值是正确的,这道题最后需要输出区间1-N的和,直接输出\small tree[1].sum的值

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100005;
struct node
{
    int l,r,sum,lazy;
}tree[maxn<<2];
void build(int l,int r,int k)    //  线段树的建立;
{
    tree[k].l=l;
    tree[k].r=r;
    tree[k].lazy=0;
    if(l==r){
        tree[k].sum=1;//初值Z=1
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
void PushUp(int k)
{
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
void PushDown(int k)//没有叠加因为是改变
{
    tree[k<<1].lazy=tree[k].lazy;
    tree[k<<1|1].lazy=tree[k].lazy;
    tree[k<<1].sum=tree[k].lazy*(tree[k<<1].r-tree[k<<1].l+1);
    tree[k<<1|1].sum=tree[k].lazy*(tree[k<<1|1].r-tree[k<<1|1].l+1);
    tree[k].lazy=0;
}

void change(int l,int r,int k,int z)
{
    if(tree[k].l==l&&tree[k].r==r)//整个区间被包含那么最大值增加1
    {
        tree[k].sum=(r-l+1)*z;
        tree[k].lazy=z;
        return;
    }
    if(tree[k].lazy) PushDown(k);//更新子节点,保证子节点的值在访问前正确
    int mid=(tree[k].r+tree[k].l)>>1;
    if(l>mid) change(l,r,k<<1|1,z);
    else if(r<=mid) change(l,r,k<<1,z);
    else{
        change(l,mid,k<<1,z);
        change(mid+1,r,k<<1|1,z);
    }
    PushUp(k);
}
/*int query(int l,int r,int k)
{
    if(tree[k].l==l&&tree[k].r==r){
        return tree[k].sum;
    }
    if(tree[k].lazy) PushDown(k);
    int mid=(tree[k].r+tree[k].l)>>1;
    if(l>mid) return query(l,r,k<<1|1);
    else if(r<=mid) return query(l,r,k<<1);
    else{
        return max(query(l,mid,k<<1),query(mid+1,r,k<<1|1));
    }
}*/
//直接输出1-N的值
int main()
{
    int t,n,m,l,r,z;
    scanf("%d",&t);
    for(int cas=1;cas<=t;++cas){
        scanf("%d%d",&n,&m);
        build(1,n,1);
        while(m--){
            scanf("%d%d%d",&l,&r,&z);
            change(l,r,1,z);
        }
        printf("Case %d: The total value of the hook is %d.\n",cas,tree[1].sum);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值