线段树(hdu3308LCIS、poj2777Count Color

hdu3308

LCIS

Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 10830 Accepted Submission(s): 4632

Problem Description
Given n integers.
You have two operations:
U A B: replace the Ath number by B. (index counting from 0)
Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b].

Input
T in the first line, indicating the case number.
Each case starts with two integers n , m(0<n,m<=105).
The next line has n integers(0<=val<=105).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=105)
OR
Q A B(0<=A<=B< n).

Output
For each Q, output the answer.

Sample Input
1
10 10
7 7 3 3 5 9 9 8 1 8
Q 6 6
U 3 4
Q 0 1
Q 0 5
Q 4 7
Q 3 5
Q 0 2
Q 4 6
U 6 10
Q 0 9

Sample Output
1
1
4
2
3
1
2
5
线段树
区间查询+单点修改

写一个结构体,每个节点中存:
l,r//存储的范围
ml,mr,m//从左第一个节点开始递增的最大长度,到右边第一个节点截止到最大长度,区间的LCIS

由于没有区间修改,不涉及push_down操作。

涉及push_up,build,change_point,ask_interval五个操作。

1.push_up:从下到上,考虑num[mid]和num[mid+1]关系。只有当前者小与后者时,取左边mr+右边ml和全区间m的最大值。
2.build
3.change_point:点修改,修改完之后push_up。
4.ask_interval:
当包含查询区间时,直接加上。
不包含时,先将答案选取左右两边的最大值。然后当num[mid]<num[mid+1]时,选取不大于区间的最大值和。

int ask_interval(int tl,int tr,int l,int r,int st){
    if(tl<=l&&r<=tr){
        return v[st].m;
    }
    int ans=0;
    if(tl<=mid) ans=max(ans,ask_interval(tl,tr,l,mid,ls));
    if(mid<tr) ans=max(ans,ask_interval(tl,tr,mid+1,r,rs));
    if(num[mid]<num[mid+1]){
        ans=max(ans,min(mid-tl+1,v[ls].mr)+min(tr-mid,v[rs].ml));
    }
    return ans;
}

全部代码:

#include <iostream>
#include "vector"
#include "string"
#include "stack"
#include "algorithm"
#include "queue"
#include "unordered_map"

#define ll long long
#define inf 0x3f3f3f3f
#define ls st<<1
#define rs st<<1|1
#define mid (l+r)/2
using namespace std;
#define MAX 100500
typedef struct {
    int l,r;
    int ml,mr,m;
}node;
node v[MAX*4];
int num[MAX];

void push_up(int st,int l,int r){
    v[st].ml=v[ls].ml;
    v[st].mr=v[rs].mr;
    v[st].m=max(v[ls].m,v[rs].m);
    v[st].l=v[ls].l;
    v[st].r=v[rs].r;
    if(num[mid]<num[mid+1]){
        if(v[rs].mr==r-mid){
            v[st].mr=v[ls].mr+v[rs].mr;
        }
        if(v[ls].ml==mid-l+1){
            v[st].ml=v[ls].ml+v[rs].ml;
        }
        v[st].m=max(v[ls].mr+v[rs].ml,v[st].m);
    }
}

void build(int l,int r,int st){
    if(l==r) {
        int x=num[l];
        v[st].l=x;
        v[st].r=x;
        v[st].ml=1;
        v[st].mr=1;
        v[st].m=1;
        return;
    }
    build(l,mid,ls);
    build(mid+1,r,rs);
    push_up(st,l,r);
}


void change_point(int x,int pos,int l,int r,int st){
    if(l==r&&l==pos) {
        v[st].l=x;
        v[st].r=x;
        v[st].ml=1;
        v[st].mr=1;
        v[st].m=1;
        return;
    }
    if(pos<=mid) change_point(x,pos,l,mid,ls);
    else change_point(x,pos,mid+1,r,rs);
    push_up(st,l,r);
}

int ask_interval(int tl,int tr,int l,int r,int st){
    if(tl<=l&&r<=tr){
        return v[st].m;
    }
    int ans=0;
    if(tl<=mid) ans=max(ans,ask_interval(tl,tr,l,mid,ls));
    if(mid<tr) ans=max(ans,ask_interval(tl,tr,mid+1,r,rs));
    if(num[mid]<num[mid+1]){
        ans=max(ans,min(mid-tl+1,v[ls].mr)+min(tr-mid,v[rs].ml));
    }
    return ans;
}


int main(){
    int t,n,m;
    int a,x,y,i;
    char c;
    cin>>t;
    while(t--) {
        cin >> n>>m;
        for (i = 1; i <= n; i++) {
            scanf("%d",&num[i]);
        }
        build(1, n, 1);
        /*for(i=1;i<=n*4;i++){
            cout<<i<<" "<<v[i].l<<" "<<v[i].r<<" "<<endl;
        }*/
        //for(i=1;i<=n;i++) cout<<v[i].m<<" "<<v[i].ml<<" "<<v[i].mr<<" "<<v[i].l<<" "<<v[i].r<< endl;
        //for(i=1;i<=n;i++) cout<<v[i].m<<" "<<v[i].ml<<" "<<v[i].mr<<" "<<v[i].l<<" "<<v[i].r<< endl;
        //cout<<ask_interval(1,n,1,n,1)<<endl;
        for(i=1;i<=m;i++){
            cin>>c>>x>>y;
            if(c=='Q') cout<<ask_interval(x+1,y+1,1,n,1)<<endl;
            else {
                num[x+1]=y;
                change_point(y,x+1,1,n,1);
            }
        }
    }



}

poj2777

Count Color

Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

There is a very long board with length L centimeter, L is a positive integer, so we can evenly divide the board into L segments, and they are labeled by 1, 2, … L from left to right, each is 1 centimeter long. Now we have to color the board - one segment with only one color. We can do following two operations on the board:

  1. “C A B C” Color the board from segment A to segment B with color C.
  2. “P A B” Output the number of different colors painted between segment A and segment B (including).

In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you may assume that the total number of different colors T is very small. To make it simple, we express the names of colors as color 1, color 2, … color T. At the beginning, the board was painted in color 1. Now the rest of problem is left to your.
Input
First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000). Here O denotes the number of operations. Following O lines, each contains “C A B C” or “P A B” (here A, B, C are integers, and A may be larger than B) as an operation defined previously.
Output
Ouput results of the output operation in order, each line contains a number.
Sample Input
2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
Sample Output
2
1

线段树
区间修改,区间查询

记录颜色,用二进制存
讲一下区间修改:
区间修改涉及到push_down
push_down:
用lazy数组存,下次经过时再加上。可以提高运行效率。
左右子区间的颜色种类都和父亲区间一样。
左右子区间lazy=1.
父亲区间lazy=0。

void push_down(int st){
    if(lazy[st]==1) {
        lazy[st]=0;
        lazy[ls]=1;
        lazy[rs]=1;
        cl[ls]=cl[st];
        cl[rs]=cl[st];
    }
}

change_interval:
当包括需要改变的区间时,赋值cl且lazy=1,退出。
push_down,改变子节点的值
当要改变的区间的左边界在mid左边时调用change_interval函数。
当要改变的区间的又边界在mid右边时调用change_interval函数。
最后push_up

void change_interval(int tl,int tr,int x,int l,int r,int st){
    if(tl<=l&&r<=tr){
        cl[st]=x;
        lazy[st]=1;
        return;
    }
    push_down(st);
    if(tl<=mid) change_interval(tl,tr,x,l,mid,ls);
    if(mid<tr) change_interval(tl,tr,x,mid+1,r,rs);
    push_up(st);
}

完整代码如下:

#include <iostream>
#include "vector"
#include "string"
#include "stack"
#include "algorithm"
#include "queue"
#include "set"
//#include "unordered_map"

#define ll long long
#define inf 0x3f3f3f3f
#define ls st<<1
#define rs st<<1|1
#define mid (l+r)/2
using namespace std;
#define MAX 100500

int cl[MAX*4];
int lazy[MAX*4];
void push_up(int st){
    cl[st]=cl[ls]|cl[rs];
}

void push_down(int st){
    if(lazy[st]==1) {
        lazy[st]=0;
        lazy[ls]=1;
        lazy[rs]=1;
        cl[ls]=cl[st];
        cl[rs]=cl[st];
    }
}

void build(int l,int r,int st){
    lazy[st]=0;
    if(l==r) {
        cl[st]=1;
        return;
    }
    build(l,mid,ls);
    build(mid+1,r,rs);
    push_up(st);
}

void change_interval(int tl,int tr,int x,int l,int r,int st){
    if(tl<=l&&r<=tr){
        cl[st]=x;
        lazy[st]=1;
        return;
    }
    push_down(st);
    if(tl<=mid) change_interval(tl,tr,x,l,mid,ls);
    if(mid<tr) change_interval(tl,tr,x,mid+1,r,rs);
    push_up(st);
}
int ans=0;
void ask_interval(int tl,int tr,int l,int r,int st){
    if(tl<=l&&r<=tr){
        ans|=cl[st];
        return;
    }
    push_down(st);
    if(tl<=mid) ask_interval(tl,tr,l,mid,ls);
    if(tr>mid) ask_interval(tl,tr,mid+1,r,rs);
}
int get_ans(int sum){
    int jojo=0;
    while(sum){
        if(sum&1) jojo++;
        sum>>=1;
    }
    return jojo;
}

int main(){
    int n,m,o,i,a,b,c;
    char jo;
    cin>>n>>m>>o;
    memset(cl,0,sizeof(cl));
    build(1,n,1);
    for(i=0;i<o;i++){
        getchar();
        scanf("%c",&jo);
        if(jo=='C'){
            scanf("%d%d%d",&a,&b,&c);
            if(a>b) swap(a,b);
            change_interval(a,b,1<<(c-1),1,n,1);
        }
        else {
            scanf("%d%d",&a,&b);
            if(a>b) swap(a,b);
            ans=0;
            ask_interval(a,b,1,n,1);
            cout<<get_ans(ans)<<endl;
        }
        //for(a=1;a<=8;a++) cout<<cl[a][1]<<" "<<cl[a][2]<<endl;
    }
}

ps:该题必须用二进制存储颜色种类,否则会超时。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值