zoukankan      html  css  js  c++  java
  • HDU 1754:I Hate It(线段树模板)

    I Hate It

    Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 102748    Accepted Submission(s): 38640

    Problem Description

    很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
    这让很多学生很反感。

    不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。

    Input

    本题目包含多组测试,请处理到文件结束。
    在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,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

    Hint

    Huge input,the C function scanf() will work better than cin

    思路

    线段树的单点更新模板题,用一个结构体记录区间的端点值,以及每个区间对应的权值。

    build函数实现了对一个区间建造以i为祖先的线段树

    update用来更新线段树

    ququery用来查询区间最大值

    详细的讲解在代码注释里

    AC代码

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <math.h>
    #include <limits.h>
    #include <map>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <set>
    #include <string>
    #define ll long long
    #define ull unsigned long long
    #define ms(a) memset(a,0,sizeof(a))
    #define pi acos(-1.0)
    #define INF 0x7f7f7f7f
    const double E=exp(1);
    const int maxn=2e5+10;
    const int mod=1e9+7;
    using namespace std;
    int MAX;
    struct wzy
    {
    	int left,right;
    	int value;//对应区间的最大值
    }p[maxn<<2];
    int father[maxn];//记录了每个点对应结构体数组的下标
    // 为区间[l,r]建立一个以i为祖先的线段树
    void build(int i,int l,int r)
    {
    	p[i].left=l;//写入第i个节点的左区间
    	p[i].right=r;//写入右区间
    	p[i].value=0;//每个区间的最大值初始为0
    	if(l==r)//当区间长度为0时,停止递归
    	{
    		father[l]=i;
    		return ;
    	}
    	// 该节点往左孩子的方向继续建立线段树
    	build(i<<1,l,(l+r)/2);
    	// 往右孩子方向建立线段树
    	build((i<<1)+1,(l+r)/2+1,r);
    }
    // 单点更新线段树
    // 从下往上更新(该点已经在函数外更新过了)
    void update(int ri)
    {
    	// 已经找到了祖先(整个线段树的祖先节点对应的下标为1)
    	if(ri==1)
    		return ;
    	// fi为ri的父亲节点
    	int fi=ri/2;
    	// 父亲节点的两个孩子
    	int l=p[fi<<1].value;
    	int r=p[(fi<<1)+1].value;
    	// 更新父亲节点的值
    	p[fi].value=max(l,r);
    	// 递归更新,从父亲节点往上找
    	update(ri/2);
    }
    // 查询区间最大值
    // 将一段区间按照建立的线段树从上往下一直拆开,直到找到和需要查询的区间完全重合停止
    // i为区间的序号,一般是1
    void query(int i,int l,int r)
    {	
    	// 找到了一个完全重合的区间
    	if(p[i].left==l&&p[i].right==r)
    	{
    		// 更新最大值
    		MAX=max(MAX,p[i].value);
    		return ;
    	}
    	// 左儿子
    	i=i<<1;
    	// 如果左区间有涉及
    	if(l<=p[i].right)
    	{
    		// 全包含在左区间内
    		if(r<=p[i].right)
    			query(i,l,r);
    		// 有部分包含在左区间内,查询区间拆分,左端点不变,右端点变成做孩子的右区间端点
    		else
    			query(i,l,p[i].right);
    	}
    	// 右儿子
    	i+=1;
    	// 和左区间的操作一样
    	if(r>=p[i].left)
    	{
    		if(l>=p[i].left)
    			query(i,l,r);
    		else
    			query(i,p[i].left,r);
    	}
    }	
    int main(int argc, char const *argv[])
    {
    	int n,m;
    	int x;
    	while(scanf("%d%d",&n,&m)!=EOF)
    	{
    		// 初始化建图
    		build(1,1,n);
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%d",&x);
    			p[father[i]].value=x;
    			// 更新线段树
    			update(father[i]);
    		}
    		char ch[3];
    		int a,b;
    		while(m--)
    		{
    			MAX=INT_MIN;
    			scanf("%s%d%d",ch,&a,&b);
    			if(ch[0]=='Q')
    			{
    				query(1,a,b);//查询a,b区间的最大值
    				cout<<MAX<<endl;
    			}
    			else
    			{
    				p[father[a]].value=b;//更新下标为father[a]的点的值
    				update(father[a]);
    			}
    		}
    	}
    	return 0;
    }
    

    上面的那种写法有点慢,因为在输入前建了一次图,输入时又建了一次图,操作重复了。下面是只建一次图的写法

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <math.h>
    #include <limits.h>
    #include <map>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <set>
    #include <string>
    #define ll long long
    #define ull unsigned long long
    #define ms(a) memset(a,0,sizeof(a))
    #define pi acos(-1.0)
    #define INF 0x7f7f7f7f
    const double E=exp(1);
    const int maxn=2e5+10;
    const int mod=1e9+7;
    using namespace std;
    #define ls o<<1
    #define rs o<<1|1
    int a[maxn];
    struct node
    {
    	int l,r;
    	int x;
    }t[maxn<<2];
    inline void push_up(int o) 
    {
        t[o].x = max(t[ls].x,t[rs].x);
    }
    void build(int l,int r,int o) 
    {
        t[o].l=l, t[o].r=r;
        if(l==r)  
    	{
    		t[o].x=a[l]; 
    		return;
    	}
        int mid=(l+r)>>1;
        build(l,mid,ls); 
        build(mid+1,r,rs);
        push_up(o);
    }
    inline void update(int s, int o, int x) 
    {
        if(t[o].l==t[o].r && t[o].l==s) 
        {
            t[o].x=x;
            return;
        }
        int mid=(t[o].l+t[o].r)>>1;
        if(s<=mid) 
        	update(s,ls,x);
        else 
        	update(s,rs,x);
        push_up(o);
    }
    inline int query(int l,int r, int o) 
    {
        if(t[o].l>=l&&t[o].r<=r) 
        {
        	return t[o].x;
        }
        int mid=(t[o].l+t[o].r)>>1;
        if(r<=mid) 
        	return query(l,r,ls);
        else if(l>mid) 
        	return query(l,r,rs);
        else 
        {
            return max(query(l,mid,ls),query(mid+1,r,rs));
        }
    }
    int main(int argc, char const *argv[])
    {
    	int n,q;
    	char ch[1];
    	while(scanf("%d%d",&n,&q)!=EOF)
    	{
    		for(int i=1;i<=n;i++)
    			scanf("%d",&a[i]);
    		build(1,n,1);
    		while(q--)
    		{
    			int L,R,X;
    			scanf("%s",ch);
    			if(ch[0]=='Q')
    			{
    				scanf("%d%d",&L,&R);
    				cout<<query(L,R,1)<<endl;
    			}
    			else
    			{
    				scanf("%d%d",&L,&X);
    				update(L,1,X);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Spark学习笔记——安装和WordCount
    Scala学习笔记——入门
    Scala学习笔记——安装
    Maven常用命令(转)
    maven中snapshot快照库和release发布库的区别和作用 (转)
    Hadoop学习笔记——WordCount
    Hadoop学习笔记——安装Hadoop
    机器学习——利用SVD简化数据
    Python自然语言处理学习——jieba分词
    机器学习——大数据与MapReduce
  • 原文地址:https://www.cnblogs.com/Friends-A/p/10324381.html
Copyright © 2011-2022 走看看