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);
}
}
}
}
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:
- “C A B C” Color the board from segment A to segment B with color C.
- “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:该题必须用二进制存储颜色种类,否则会超时。