HDU 1166 敌兵布阵 (单点更新,区间求和)
接下来每行有一条命令,命令有4种形式:(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
const int Max_N = 50100 ;
int sum[Max_N<<2] , x[Max_N] ;
void push_up(int root){
sum[root] = sum[root<<1] + sum[root<<1|1] ;
}
void make_tree(int L , int R , int root){
if(L == R){
sum[root] = x[L] ;
return ;
}
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
push_up(root) ;
}
void update(int id , int c , int L , int R , int root){
if(L == R){
sum[root] += c ;
return ;
}
int mid = (L + R) >> 1 ;
if(id <= mid)
update(id , c , L , mid ,root<<1) ;
else
update(id , c , mid+1 , R , root<<1|1) ;
push_up(root) ;
}
int query(int l , int r , int L , int R ,int root){
if(l <= L && R <= r)
return sum[root] ;
int mid = (L + R) >> 1 ;
int ans = 0 ;
if(l <= mid)
ans += query(l , r , L , mid , root<<1) ;
if(r > mid)
ans += query(l , r , mid+1 , R , root<<1|1) ;
return ans ;
}
int main(){
int T , n , i , a , b ;
char str[8] ;
cin>>T ;
for(int cas = 1 ; cas <= T ; cas++){
printf("Case %d:\n",cas) ;
scanf("%d",&n) ;
for(i = 1 ; i <= n ; i++)
scanf("%d",&x[i]) ;
make_tree(1,n,1) ;
while(scanf("%s",str) && strcmp(str,"End")!=0){
scanf("%d%d",&a,&b) ;
if(str[0] == 'A')
update(a , b , 1 , n , 1) ;
else if(str[0] == 'S')
update(a , -b , 1 , n , 1) ;
else
printf("%d\n",query(a , b , 1 , n , 1)) ;
}
}
return 0 ;
}
HDU 1394 Minimum Inversion Number (逆序对 , 单点更新,区间求和)
序列的N个置换,求N串中逆序对最小的值。a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
You are asked to write a program to find the minimum inversion number out of the above sequences.
const int Max_N = 5008 ;
int Sum[Max_N<<1] ,x[Max_N];
void push_up(int root){
Sum[root] = Sum[root<<1] + Sum[root<<1|1] ;
}
void make_tree(int L , int R , int root){
if(L == R){
Sum[root] = 0 ;
return ;
}
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
push_up(root) ;
}
void update(int id , int L , int R , int root){
if(L == R){
Sum[root]++ ;
return ;
}
int mid = (L + R) >> 1 ;
if(id <= mid)
update(id , L , mid , root<<1) ;
else
update(id , mid+1 , R , root<<1|1) ;
push_up(root) ;
}
int query(int l , int r , int L , int R , int root){
if(l <= L && R <= r)
return Sum[root] ;
int mid = (L + R) >> 1 ;
int ans = 0 ;
if(l <= mid)
ans += query(l , r , L , mid , root<<1) ;
if(r > mid)
ans += query(l , r , mid+1 , R , root<<1|1) ;
return ans ;
}
int main(){
int n , i , sum , ans ;
while(cin>>n){
make_tree(1 , n , 1) ; //建一颗空树
sum = 0 ;
for(i = 1 ; i <= n ; i++){
scanf("%d",&x[i]) ;
x[i]++ ; // 序列变为[1,n]
sum += query(x[i] , n , 1 , n , 1) ; // [x[i] , n]出现的个数之和 , 也就是在大于x[i],且位置在起左边的个数
update(x[i] , 1 , n , 1) ; //在x[i]位置插入1
}
ans = sum ; // sum即为初始序列逆序数
for(i = 1 ; i < n ; i++){
// 将想x[i]移到尾巴。逆序数变化情况。 x[i]在头少了(x[i] -1 ) ,x[i] 在尾多了(n-x[i])个 ,总计多了: +(n-x[i])-(x[i]-1)
sum = sum + n - x[i] - x[i] + 1 ;
ans = min(ans ,sum) ;
}
printf("%d\n",ans) ;
}
return 0 ;
}
HDU 1754 I Hate It (单点更新,区间最值)
接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
Output
对于每一次询问操作,在一行里面输出最高成绩。
Sample Input
5 61 2 3 4 5Q 1 5U 3 6Q 3 4Q 4 5U 2 9Q 1 5
Sample Output
5 6 5 9
const int Max_N = 200100 ;
int Max[Max_N<<2] , x[Max_N] ;
void push_up(int root){
Max[root] = max(Max[root<<1] , Max[root<<1|1]) ;
}
void make_tree(int L , int R , int root){
if(L == R){
Max[root] = x[L] ;
return ;
}
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
push_up(root) ;
}
void update(int id , int c , int L , int R , int root){
if(L == R){
Max[root] = c ;
return ;
}
int mid = (L + R) >> 1 ;
if(id <= mid)
update(id , c , L , mid ,root<<1) ;
else
update(id , c , mid+1 , R ,root<<1|1) ;
push_up(root) ;
}
int query(int l , int r , int L , int R , int root){
if(l <= L && R <= r)
return Max[root] ;
int mid = (L + R) >> 1 ;
int ans = -1 ;
if(l <= mid)
ans = max(ans , query(l , r , L , mid , root<<1)) ;
if(r > mid)
ans = max(ans , query(l , r , mid+1 , R , root<<1|1)) ;
return ans ;
}
int main(){
int n , m , i , a , b ;
char str[2] ;
while(cin>>n>>m){
for(i = 1 ; i <= n ; i++)
scanf("%d",&x[i]) ;
make_tree(1 , n , 1) ;
while(m--){
scanf("%s%d%d",str,&a,&b) ;
if(*str == 'U')
update(a , b , 1 , n , 1) ;
else
printf("%d\n",query(a , b , 1 , n , 1)) ;
}
}
return 0 ;
}
POJ 4047 区间更新 , 区间最值
const int Max_N = 200010 ;
int x[Max_N] , sum[Max_N] , num[Max_N] ;
int N , K ;
int _max[Max_N<<2] , add[Max_N<<2] ;
void push_up(int root){
_max[root] = max(_max[root<<1] , _max[root<<1|1]) ;
}
void push_down(int root){
if(add[root]){
add[root<<1] += add[root] ;
add[root<<1|1] += add[root] ;
_max[root<<1] += add[root] ;
_max[root<<1|1] += add[root] ;
add[root] = 0 ;
}
}
void make_tree(int L , int R , int root){
add[root] = 0 ;
if(L == R){
_max[root] = num[L] ;
return ;
}
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
push_up(root) ;
}
void update(int l , int r , int c , int L , int R , int root){
if(l <= L && R <= r){
add[root] += c ;
_max[root] += c ;
return ;
}
push_down(root) ;
int mid = (L + R) >> 1 ;
if(l <= mid)
update(l , r , c , L , mid , root<<1) ;
if(r > mid)
update(l , r , c , mid+1 , R , root<<1|1) ;
push_up(root) ;
}
int query(int l , int r , int L , int R , int root){
if(l <= L && R <= r)
return _max[root] ;
push_down(root) ;
int mid = (L + R) >> 1 ;
int ans = -0xfffffff ;
if(l <= mid)
ans = max(ans, query(l , r , L , mid , root<<1) ) ;
if(r > mid)
ans = max(ans , query(l , r , mid+1 , R , root<<1|1) );
return ans ;
}
int main(){
int t , i , j , M , a , b , c , p ;
scanf("%d" ,&t) ;
while(t--){
scanf("%d%d%d" ,&N ,&M ,&K) ;
sum[0] = 0 ;
for(i = 1 ; i <= N ; i++){
scanf("%d" ,&x[i]) ;
sum[i] = x[i] + sum[i-1] ;
}
for(i = K ; i <= N ; i++)
num[i-K+1] = sum[i] - sum[i-K] ;
N = N - K + 1 ;
make_tree(1 , N , 1) ;
while(M--){
scanf("%d%d%d" ,&p , &a , &b) ;
if(p == 0){
if(x[a] != b){
c = b - x[a] ;
x[a] = b ;
update(max(a-K+1,1) , a , c , 1 , N , 1) ;
}
}
else if(p == 1){
if(a != b){
c = x[b] - x[a] ;
update(max(a-K+1,1) , a , c , 1 , N , 1) ;
c = x[a] - x[b] ;
update(max(b-K+1,1) , b , c , 1 , N , 1) ;
swap(x[a] , x[b]) ;
}
}
else{
printf("%d\n" , query(a, b-K+1 , 1 , N , 1)) ;
}
}
}
return 0 ;
}
Codeforces 91B. Queue (区间“最值”)
There are n walruses standing in a queue in an airport. They are numbered starting from the queue's tail: the 1-st walrus stands at the end of the queue and the n-th walrus stands at the beginning of the queue. The i-th walrus has the age equal to ai.
The i-th walrus becomes displeased if there's a younger walrus standing in front of him, that is, if exists such j (i < j), that ai > aj. Thedispleasure of the i-th walrus is equal to the number of walruses between him and the furthest walrus ahead of him, which is younger than the i-th one. That is, the further that young walrus stands from him, the stronger the displeasure is.
The airport manager asked you to count for each of n walruses in the queue his displeasure.
The first line contains an integer n (2 ≤ n ≤ 105) — the number of walruses in the queue. The second line contains integers ai (1 ≤ ai ≤ 109).
Note that some walruses can have the same age but for the displeasure to emerge the walrus that is closer to the head of the queue needs to be strictly younger than the other one.
Print n numbers: if the i-th walrus is pleased with everything, print "-1" (without the quotes). Otherwise, print the i-th walrus's displeasure: the number of other walruses that stand between him and the furthest from him younger walrus.
6 10 8 5 3 50 45
2 1 0 -1 0 -1
7 10 4 6 3 2 8 15
4 2 1 0 -1 -1 -1
5 10 3 1 10 11
1 0 -1 -1 -1
题意:
有n个数的失望值,id失望值的定义是:id右边离它最远的且比它小的数 与 它本身之间 间隔的数的数量;
线段树,结点保存区间最小值 每次将当前的数更新为INF,然后查找整个区间内最右边的比它小的数的下标 .
const int Max_N = 100008 ;
const int inf = 1000000800 ;
int _Min[Max_N<<2] , x[Max_N] , ans[Max_N] ;
void push_up(int root){
_Min[root] = min(_Min[root<<1] , _Min[root<<1|1]) ;
}
void make_tree(int L , int R , int root){
if(L == R){
_Min[root] = x[L] ;
return ;
}
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
push_up(root) ;
}
void update(int id , int L , int R , int root){
if(L == R){
_Min[root] = inf ;
return ;
}
int mid = (L + R) >> 1 ;
if(id <= mid)
update(id , L , mid , root<<1) ;
else
update(id , mid+1 , R , root<<1|1) ;
push_up(root) ;
}
//求区间[L,R]中 比C小 且 下标最大 的下标 。 其实二叉树遍历蛮重要的。 先右->后左。{好像不是3种遍历方式哦!}
int query(int c , int L , int R , int root){
if(L == R)
return L ;
int mid = (L + R) >> 1 ;
if(_Min[root<<1|1] < c) //右孩子的最小值比C小,则在右孩子中找 。
return query(c , mid+1 , R , root<<1|1) ;
else
return query(c , L , mid , root<<1) ;
}
int main(){
int n , i ;
cin>>n ;
for(i = 1 ; i <= n ; i++)
scanf("%d" , &x[i]) ;
make_tree(1 , n , 1) ;
for(i = 1 ; i <= n ; i++){
update(i , 1 , n , 1) ; //将i处更新最大,更新完之后,_Min[1] = [1,n]最小值
if(_Min[1] < x[i])
ans[i] = query(x[i] , 1 , n , 1) - i - 1 ; // 为什么不能是query(x[i] , i , n , 1) ?因为[i,n]的节点编号不是1。注意这里
else
ans[i] = -1 ;
}
printf("%d" , ans[1]) ;
for(i = 2 ; i <= n ; i++)
printf(" %d" , ans[i]) ;
puts("") ;
return 0 ;
}
hdu 1698 (区间更新)
Just a Hook
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.
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.
typedef long long LL ;
const int Max_N = 100008 ;
int sum[Max_N<<2] ; /*和*/
int color[Max_N<<2] ;/*颜色,-1表示不是纯色*/
/*向上更新,计算和*/
void push_up(int root){
sum[root] = sum[root<<1] + sum[root<<1|1] ;
}
/*lazy操作,向下更新时,把纯色的颜色传递下去,同时更新和,若不是纯色则孩子节点的颜色之前已经更新*/
void push_down(int root ,int L ,int R){
if(color[root] != -1){
color[root<<1] = color[root<<1|1] = color[root] ;
color[root] = -1 ; /*向下更新就是因为root节点不再纯色*/
int mid = (L+R)>>1 ;
sum[root<<1] = (mid-L+1) * color[root<<1] ;
sum[root<<1|1] = (R-mid) * color[root<<1|1] ;
}
}
/*建树*/
void make_tree(int L , int R , int root){
color[root] = 1 ;
if(L == R){
sum[root] = 1 ;
return ;
}
int mid = (L+R)>>1 ;
make_tree(L,mid,root<<1) ;
make_tree(mid+1,R,root<<1|1) ;
push_up(root) ;
}
/*更新区间[l,r]颜色为c*/
void update(int l , int r , int c ,int L ,int R ,int root){
if(l <= L && R <= r){
color[root] = c ;
sum[root] = (R-L+1) * c ;
return ;
}
push_down(root,L,R) ;
int mid = (L+R)>>1 ;
if(l <= mid)
update(l,r,c,L,mid,root<<1) ;
if(r > mid)
update(l,r,c,mid+1,R,root<<1|1) ;
push_up(root) ;
}
int main(){
int T ,cas , n ,q , l ,r ,c;
scanf("%d",&T) ;
for(cas = 1 ; cas <= T ; cas++){
scanf("%d",&n) ;
make_tree(1,n,1) ;
scanf("%d",&q) ;
while(q--){
scanf("%d%d%d",&l,&r,&c) ;
update(l,r,c,1,n,1) ;
}
printf("Case %d: The total value of the hook is %d.\n",cas,sum[1]) ;
}
return 0 ;
}
fzu1608 Huge Mission (区间更新,区间最值)
区间【L, R】染色c ,每个点都取最大值。
求整个区间最大和。
const int Max_N = 50008 ;
int color[Max_N<<2] ;
void push_down(int root){
if(color[root] != -1){
color[root<<1] = max(color[root<<1],color[root]) ;
color[root<<1|1] = max(color[root<<1|1],color[root]) ;
color[root] = -1 ;
}
return ;
}
void make_tree(int L , int R , int root){
color[root] = 0 ;
if(L == R)
return ;
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
}
void update(int l , int r , int c , int L , int R , int root){
if(l <= L && R <= r){
if(color[root] < c)
color[root] = c ;
return ;
}
push_down(root) ;
int mid = (L + R) >> 1 ;
if(l <= mid)
update(l , r , c , L , mid , root<<1) ;
if(r > mid)
update(l , r , c , mid+1 , R , root<<1|1) ;
}
int query(int L , int R , int root){
if(L == R)
return color[root] ;
push_down(root) ;
int mid = (L + R) >> 1 ;
return query(L , mid , root<<1) + query(mid+1 , R ,root<<1|1) ;
}
int main(){
int n , m , l , r , c ;
while(scanf("%d%d" ,&n ,&m) != EOF){
make_tree(0 , n , 1) ;
while(m--){
l = getint() ;
r = getint() ;
c = getint() ;
if(c)
update(l , r-1 , c , 0 , n , 1) ;
}
printf("%d\n" , query(0 , n , 1)) ;
}
return 0 ;
}
POJ 3468 (区间更新)
Time Limit: 5000MS | Memory Limit: 131072K | |
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.
Output
You need to answer all Q commands in order. One answer in a line.
Sample Input
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4
Sample Output
4 55 9 15
Hint
typedef long long LL ;
const int Max_N = 101000 ;
LL sum[Max_N<<2] , add[Max_N<<2] , x[Max_N];
void push_up(int root){
sum[root] = sum[root<<1] + sum[root<<1|1] ;
}
void push_down(int L ,int R ,int root){
if(add[root]){ //纯色才向下更新。
add[root<<1] += add[root] ;
add[root<<1|1] += add[root] ;
int mid = (L + R)>>1 ;
sum[root<<1] += add[root]*(mid-L+1) ;
sum[root<<1|1] += add[root]*(R-mid) ;
add[root] = 0 ; //更新完便不再是纯色了。
}
}
void make_tree(int L ,int R,int root){
add[root] = 0 ;
if(L == R){
sum[root] = x[L] ;
return ;
}
int mid = (L + R)>>1 ;
make_tree(L,mid,root<<1) ;
make_tree(mid+1,R,root<<1|1) ;
push_up(root) ;
}
void update(int l ,int r ,LL c ,int L ,int R ,int root){
if(l <= L && R <= r){
add[root] += c ;
sum[root] += c*(R-L+1) ;
return ;
}
push_down(L,R,root) ;
int mid = (L + R)>>1 ;
if(l <= mid)
update(l,r,c,L,mid,root<<1) ;
if(r > mid)
update(l,r,c,mid+1,R,root<<1|1) ;
push_up(root) ;
}
LL query(int l ,int r ,int L ,int R ,int root){
if(l <= L && R <= r)
return sum[root] ;
push_down(L,R,root) ; // update中push_down的时候并没有把所有该更新的更新完。
int mid = (L + R)>>1 ;
LL ans = 0 ;
if(l <= mid)
ans += query(l,r,L,mid,root<<1) ;
if(r > mid)
ans += query(l,r,mid+1,R,root<<1|1) ;
return ans ;
}
int main(){
int i , n , q ,l,r;
LL c;
char str[2] ;
cin>>n>>q ;
for(i = 1 ; i <= n ; i++)
scanf("%lld",&x[i]) ;
make_tree(1,n,1) ;
while(q--){
scanf("%s%d%d",str,&l,&r) ;
if(str[0] == 'Q')
printf("%lld\n",query(l,r,1,n,1)) ;
else{
scanf("%lld",&c) ;
update(l,r,c,1,n,1) ;
}
}
return 0 ;
}
HDU 4027 Can you answer these queries?(区间更新)
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
You are asked to answer the queries that the sum of the endurance of a consecutive part of the battleship line.
Notice that the square root operation should be rounded down to integer.
For each test case, the first line contains a single integer N, denoting there are N battleships of evil in a line. (1 <= N <= 100000)
The second line contains N integers Ei, indicating the endurance value of each battleship from the beginning of the line to the end. You can assume that the sum of all endurance value is less than 2 63.
The next line contains an integer M, denoting the number of actions and queries. (1 <= M <= 100000)
For the following M lines, each line contains three integers T, X and Y. The T=0 denoting the action of the secret weapon, which will decrease the endurance value of the battleships between the X-th and Y-th battleship, inclusive. The T=1 denoting the query of the commander which ask for the sum of the endurance value of the battleship between X-th and Y-th, inclusive.
typedef long long LL ;
const int Max_N = 100100 ;
LL sum[Max_N<<2] , x[Max_N] ;
int color[Max_N<<2] ;
void push_up(int root){
sum[root] = sum[root<<1] + sum[root<<1|1] ;
color[root] = color[root<<1] && color[root<<1|1] ;
}
void make_tree(int L , int R , int root){
if(L == R){
sum[root] = x[L] ;
color[root] = sum[root] == 1 ;
return ;
}
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
push_up(root) ;
}
void update(int l , int r , int L , int R , int root){
if(color[root])
return ;
if(L == R){
sum[root] = LL (sqrt(sum[root])) ;
color[root] = sum[root] == 1 ;
return ;
}
int mid = (L + R) >> 1 ;
if(l <= mid)
update(l , r , L , mid , root<<1) ;
if(r > mid)
update(l , r , mid+1 , R , root<<1|1) ;
push_up(root) ;
}
LL query(int l , int r , int L , int R , int root){
if(l <= L && R <= r)
return sum[root] ;
int mid = (L + R) >> 1 ;
LL ans = 0 ;
if(l <= mid)
ans += query(l , r , L , mid , root<<1) ;
if(r > mid)
ans += query(l , r , mid+1 , R , root<<1|1) ;
return ans ;
}
int main(){
int n , i , q , k = 1 , t , l , r;
while(cin>>n){
printf("Case #%d:\n" , k++) ;
for(i = 1 ; i <= n ; i++)
scanf("%I64d",&x[i]) ;
make_tree(1 , n , 1) ;
scanf("%d",&q) ;
while(q--){
scanf("%d%d%d",&t,&l,&r) ;
if(l > r)
swap(l , r) ;
if(t)
printf("%I64d\n",query(l , r , 1 , n , 1)) ;
else
update(l , r , 1 , n , 1) ;
}
puts("") ;
}
return 0 ;
}
http://codeforces.com/problemset/problem/292/E (区间更新)
题目大意:两个数组,a和b,两种操作:
1:将数组a的区间[x,x+k-1]复制给数组b的区间[y,y+k-1]。
2:问当前b[x]的值。
const int Max_N = 100008 ;
int Pos[Max_N<<2] ; //区间左端映射到数组A下标的起点
void push_down(int root , int L , int R){
if(Pos[root]){
int mid = (L + R) >> 1 ;
Pos[root<<1] = Pos[root] ;
Pos[root<<1|1] = mid + 1 + Pos[root] - L ;
Pos[root] = 0 ;
}
}
void make_tree(int L , int R , int root){
Pos[root] = 0 ;
if(L == R)
return ;
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
}
void update(int l , int r , int start , int L , int R , int root){
if(l == L && R == r){
Pos[root] = start ;
return ;
}
push_down(root , L , R) ;
int mid = (L + R) >> 1 ;
if(r <= mid)
update(l , r , start , L , mid , root<<1) ;
else if(l > mid)
update(l , r , start , mid+1 , R , root<<1|1) ;
else{
update(l , mid , start , L , mid , root<<1) ;
update(mid+1 , r , start+mid+1-l , mid+1 , R ,root<<1|1) ;
}
}
int query(int id , int L , int R , int root){
if(L == R)
return Pos[root] ;
push_down(root , L , R) ;
int mid = (L + R) >> 1 ;
if(id <= mid)
return query(id , L , mid , root<<1) ;
else
return query(id , mid+1 , R , root<<1|1) ;
}
int A[Max_N] , B[Max_N] ;
int main(){
int i ,t , n , m , x , y , k;
cin>>n>>m ;
for(i = 1 ; i <= n ; i++)
scanf("%d" , &A[i]) ;
for(i = 1 ; i <= n ; i++)
scanf("%d" , &B[i]) ;
make_tree(1 , n , 1) ;
while(m--){
scanf("%d%d" , &t , &x) ;
if(t == 1){
scanf("%d%d" , &y , &k) ;
update(y , y+k-1 , x , 1 , n , 1) ;
}
else{
int id = query(x , 1 , n , 1) ;
printf("%d\n" , id ? A[id] : B[x]) ;
}
}
return 0 ;
}
染色问题,题目1496:数列区间
题目描述:接下来我们会对其进行m(1<=m<=100000)次操作,每次操作都会将区间[l,r]内的所有数字都变为一个特定的数字,并且每次操作这个特定的数字都不相同。
我们可以简单的认为,第一次操作时将给定区间内的数字都变为1,第二次将给定区间内数字都变为2,第三次变为3,以此类推。
在经过m次操作完成后,要求输出该数列中,拥有相同正整数(不包括0)的最长连续区间长度。
若n = 5,m = 3,原数列00000
第一次操作区间[1,3],
数列变为11100
第二次操作区间[3,4],
数列变为11220
第三次操作区间[3,5]
数列变为11333
则最长连续区间为[3,5]拥有共同正整数3,故输出其长度3。
输入:
接下去m行,每行两个整数l,r,表示该次操作区间为[l,r]。(1<=l<=r<=n)
输出:
样例输入:
5 3
1 3
3 4
3 5
5 2
1 3
1 5
样例输出:
3
5
区间更新;
lazy标记
const int Max_N = 1000008 ;
int color[Max_N<<2] , final_color[Max_N] ;
void push_down(int root){
if(color[root]){
color[root<<1] = color[root<<1|1] = color[root] ;
color[root] = 0 ;
}
}
void make_tree(int L , int R , int root){
color[root] = 0 ;
if(L == R)
return ;
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
}
void update(int l , int r , int c , int L , int R , int root){
if(l <= L && R <= r){
color[root] = c ;
return ;
}
push_down(root) ;
int mid = (L + R) >> 1 ;
if(l <= mid)
update(l , r , c , L , mid , root<<1) ;
if(r > mid)
update(l , r , c , mid+1 , R , root<<1|1) ;
}
void query(int L , int R , int root){
if(L == R){
final_color[L] = color[root] ;
return ;
}
push_down(root) ;
int mid = (L + R) >> 1 ;
query(L , mid , root<<1) ;
query(mid+1 , R , root<<1|1) ;
}
int Ans(int N){
int ans = 0 ;
int now = final_color[1] , num = 1 ;
for(int i = 2 ; i <= N ; i++){
if(final_color[i] == now)
num++ ;
else{
if(now)
ans = max(ans , num) ;
now = final_color[i] ;
num = 1 ;
}
}
if(now)
ans = max(ans , num) ;
return ans ;
}
int main(){
int n , m , i , l , r;
while(scanf("%d%d" , &n ,&m) != EOF){
make_tree(1 , n , 1) ;
for(i = 1 ; i <= m ; i++){
scanf("%d%d" , &l , &r) ;
if(l > r)
swap(l , r) ;
update(l , r , i , 1 , n , 1) ;
}
query(1 , n , 1) ;
printf("%d\n" , Ans(n)) ;
}
return 0 ;
}
POJ 3667 Hotel 区间合并
输入 2 a b:将[a,a+b-1]的房间清空思路:记录区间中最长的空房间
输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边
const int Max_N = 55558 ;
int l_can[Max_N<<2] , r_can[Max_N<<2] , all_can[Max_N<<2] , color[Max_N<<2] ;
void make_tree(int L , int R , int root){
l_can[root] = r_can[root] = all_can[root] = R - L + 1 ;
color[root] = -1 ;
if(L == R)
return ;
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
}
void push_down(int L , int R , int root){
if(color[root] != -1){
color[root<<1] = color[root<<1|1] = color[root] ;
int mid = (L + R) >> 1 ;
l_can[root<<1] = r_can[root<<1] = all_can[root<<1] = (color[root] ? mid-L+1 : 0) ;
l_can[root<<1|1] = r_can[root<<1|1] = all_can[root<<1|1] = (color[root] ? R - mid : 0) ;
color[root] = -1 ;
}
}
void push_up(int L , int R , int root){
l_can[root] = l_can[root<<1] ;
r_can[root] = r_can[root<<1|1] ;
int mid = (L + R) >> 1 ;
if(l_can[root] == mid - L + 1)
l_can[root] += l_can[root<<1|1] ;
if(r_can[root] == R - mid)
r_can[root] += r_can[root<<1] ;
all_can[root] = max(max(all_can[root<<1] , all_can[root<<1|1]) ,
r_can[root<<1] + l_can[root<<1|1]) ;
}
void update(int l , int r , int c , int L , int R , int root){
if(l <= L && R <= r){
l_can[root] = r_can[root] = all_can[root] = (c? R-L+1 : 0) ;
color[root] = c ;
return ;
}
push_down(L , R , root) ;
int mid = (L + R) >> 1 ;
if(l <= mid)
update(l , r ,c , L , mid , root<<1) ;
if(r > mid)
update(l , r ,c , mid+1 , R , root<<1|1) ;
push_up(L , R , root) ;
}
int query(int len , int L , int R , int root){
if(L == R)
return L ;
push_down(L , R , root) ;
int mid = (L + R) >> 1 ;
if(len <= all_can[root<<1])
return query(len , L , mid , root<<1) ;
else if(len <= r_can[root<<1]+ l_can[root<<1|1])
return mid - r_can[root<<1] + 1 ;
else
return query(len , mid+1 , R , root<<1|1) ;
}
int main(){
int n , m , k , x , y , id ;
scanf("%d%d" ,&n , &m) ;
make_tree(1 , n , 1) ;
while(m--){
scanf("%d%d" ,&k ,&x) ;
if(k == 1){
if(all_can[1] < x)
puts("0") ;
else{
id = query(x , 1 , n , 1) ;
printf("%d\n" ,id) ;
update(id , id + x -1 , 0 , 1 , n , 1) ;
}
}
else{
scanf("%d" , &y) ;
update(x , x+y-1 , 1 , 1 , n , 1) ;
}
}
return 0 ;
}
http://codeforces.com/problemset/problem/46/D (区间合并)
题目大意:
有一条长度为L的街道,有N个操作,操作有两种:
(1)"1 a",表示有一辆长度为a的车开进来想找停车位;
停车位必须满足与它前面的车距离至少为b,与后面的车距离至少为f;
如果能找到这样的停车位;输出这辆车的起始位置(且这个位置最小),否则输出-1;
(2)"2 a",表示第a个事件里进来停车的那辆车开出去了;
算法思想:
建立起点为-b,终点为L+f的线段树;
查找的时候,直接查找len+b+f的线段就可以了;
注意这里存的是坐标点个数,而不是线段长度。
1 //节点个数 2 const int Max_N = 100300 ; 3 int L_canuse[Max_N<<2] , R_canuse[Max_N<<2] , All_canuse[Max_N<<2] , color[Max_N<<2] ; 4 5 void make_tree(int L , int R , int root){ 6 L_canuse[root] = R_canuse[root] = All_canuse[root] = R - L + 1 ; 7 color[root] = -1 ; 8 if(L == R) 9 return ; 10 int mid = (L + R) >> 1 ; 11 make_tree(L , mid , root<<1) ; 12 make_tree(mid+1 , R , root<<1|1) ; 13 } 14 15 void push_up(int root , int L , int R){ 16 L_canuse[root] = L_canuse[root<<1] ; 17 R_canuse[root] = R_canuse[root<<1|1] ; 18 int mid = (L + R) >> 1 ; 19 if(L_canuse[root] == mid - L + 1) 20 L_canuse[root] += L_canuse[root<<1|1] ; 21 if(R_canuse[root] == R - mid) 22 R_canuse[root] += R_canuse[root<<1] ; 23 All_canuse[root] = max(max(All_canuse[root<<1] , All_canuse[root<<1|1]), 24 R_canuse[root<<1] + L_canuse[root<<1|1]) ; 25 } 26 27 void push_down(int root , int L , int R){ 28 if(color[root] != -1){ 29 color[root<<1] = color[root<<1|1] = color[root] ; 30 int mid = (L + R) >> 1 ; 31 L_canuse[root<<1] = R_canuse[root<<1] = All_canuse[root<<1] = (color[root]? mid - L + 1 : 0) ; 32 L_canuse[root<<1|1] = R_canuse[root<<1|1] = All_canuse[root<<1|1] = (color[root]? R - mid : 0) ; 33 color[root] = -1 ; 34 } 35 } 36 37 void update(int l , int r , int c , int L , int R , int root){ 38 if(l <= L && R <= r){ 39 L_canuse[root] = R_canuse[root] = All_canuse[root] = (c? R - L + 1 : 0) ; 40 color[root] = c ; 41 return ; 42 } 43 push_down(root , L , R) ; 44 int mid = (L + R) >> 1 ; 45 if(l <= mid) 46 update(l , r , c , L , mid , root<<1) ; 47 if(r > mid) 48 update(l , r , c , mid+1 , R , root<<1|1) ; 49 push_up(root , L , R) ; 50 } 51 52 int query(int x , int L , int R , int root){ 53 if(L == R) 54 return L ; 55 push_down(root , L , R) ; 56 int mid = (L + R) >> 1 ; 57 if(x <= All_canuse[root<<1]) 58 return query(x , L , mid , root<<1) ; 59 else if(x <= R_canuse[root<<1] + L_canuse[root<<1|1]) 60 return mid - R_canuse[root<<1] + 1 ; 61 else 62 return query(x , mid+1 , R , root<<1|1) ; 63 } 64 65 struct Car{ 66 int Start ; 67 int Len ; 68 }car[108]; 69 70 int main(){ 71 int n ,L , B , F , t , x ; 72 cin>>L>>B>>F; 73 make_tree(-B , L+F , 1) ; 74 cin>>n ; 75 for(int i = 1 ; i <= n ; i++){ 76 cin>>t>>x ; 77 if(t == 1){ 78 car[i].Len = x ; 79 if(All_canuse[1] < x + B + F + 1) 80 puts("-1") ; 81 else{ 82 car[i].Start = query(x+B+F , -B , L+F , 1) + B ; 83 update(car[i].Start , car[i].Start + car[i].Len - 1, 0 , -B , L+F , 1) ; 84 printf("%d\n",car[i].Start) ; 85 } 86 } 87 else 88 update(car[x].Start , car[x].Start + car[x].Len - 1 , 1 , -B , L+F , 1) ; 89 } 90 return 0 ; 91 }
hdu 1504 (区间合并)
Tunnel Warfare
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3609 Accepted Submission(s): 1377
Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!
There are three different events described in different format shown below:
D x: The x-th village was destroyed.
Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.
R: The village destroyed last was rebuilt.
/*区间合并*/
typedef long long LL ;
const int Max_N = 50100 ;
/*Left[i] ,到节点i左端点连续村庄的个数 ,Right[i] ,到节点i右端点连续村庄的个数 */
int Left[Max_N<<2] , Right[Max_N<<2] ;
void push_up(int L , int R , int root){
Left[root] = Left[root<<1] ;
Right[root] = Right[root<<1|1] ;
int mid = (L + R) >> 1 ;
if(Left[root] == mid - L + 1)
Left[root] += Left[root<<1|1] ;
if(Right[root] == R - mid)
Right[root] += Right[root<<1] ;
}
void make_tree(int L ,int R ,int root){
Left[root] = Right[root] = R - L + 1 ;
if(L == R)
return ;
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
}
void update(int id , int type , int L , int R , int root){
if(L == R){
Left[root] = Right[root] = type ;
return ;
}
int mid = (L + R) >> 1 ;
if(id <= mid)
update(id , type , L , mid , root<<1) ;
else
update(id , type , mid + 1 , R ,root<<1|1) ;
push_up(L , R , root) ;
}
int query(int id , int L , int R , int root){
if(L == R)
return Left[root] ;
int mid = (L + R) >> 1 ;
if(id <= mid){
if(Left[root<<1] == mid - L + 1)
return Left[root<<1] + Left[root<<1|1] ;
else if(L + Left[root<<1] > id)
return Left[root<<1] ;
else if(id > mid - Right[root<<1])
return Right[root<<1] + Left[root<<1|1] ;
else
return query(id , L , mid , root<<1) ;
}
else{
if(Right[root<<1|1] == R - mid)
return Right[root<<1|1] + Right[root<<1] ;
else if(id > R - Right[root<<1|1])
return Right[root<<1|1] ;
else if(mid + 1 + Left[root<<1|1] > id)
return Right[root<<1] + Left[root<<1|1] ;
else
return query(id , mid+1 , R , root<<1|1) ;
}
}
int main(){
int n , m , id ;
stack<int> me ;
char str[2] ;
while(cin>>n>>m){
while(!me.empty())
me.pop() ;
make_tree(1,n,1) ;
while(m--){
scanf("%s" , str) ;
if(str[0] == 'D'){
scanf("%d",&id) ;
update(id , 0 , 1 , n , 1) ;
me.push(id) ;
}
else if(str[0] == 'R'){
if(!me.empty()){
update(me.top() , 1 , 1 , n , 1) ;
me.pop() ;
}
}
else{
scanf("%d",&id) ;
printf("%d\n",query(id,1,n,1)) ;
}
}
}
return 0 ;
}
const int Max_N = 1000008 ;
int color[Max_N<<2] , final_color[Max_N] ;
void push_down(int root){
if(color[root]){
color[root<<1] = color[root<<1|1] = color[root] ;
color[root] = 0 ;
}
}
void make_tree(int L , int R , int root){
color[root] = 0 ;
if(L == R)
return ;
int mid = (L + R) >> 1 ;
make_tree(L , mid , root<<1) ;
make_tree(mid+1 , R , root<<1|1) ;
}
void update(int l , int r , int c , int L , int R , int root){
if(l <= L && R <= r){
color[root] = c ;
return ;
}
push_down(root) ;
int mid = (L + R) >> 1 ;
if(l <= mid)
update(l , r , c , L , mid , root<<1) ;
if(r > mid)
update(l , r , c , mid+1 , R , root<<1|1) ;
}
void query(int L , int R , int root){
if(L == R){
final_color[L] = color[root] ;
return ;
}
push_down(root) ;
int mid = (L + R) >> 1 ;
query(L , mid , root<<1) ;
query(mid+1 , R , root<<1|1) ;
}
int Ans(int N){
int ans = 0 ;
int now = final_color[1] , num = 1 ;
for(int i = 2 ; i <= N ; i++){
if(final_color[i] == now)
num++ ;
else{
if(now)
ans = max(ans , num) ;
now = final_color[i] ;
num = 1 ;
}
}
if(now)
ans = max(ans , num) ;
return ans ;
}
int main(){
int n , m , i , l , r;
while(scanf("%d%d" , &n ,&m) != EOF){
make_tree(1 , n , 1) ;
for(i = 1 ; i <= m ; i++){
scanf("%d%d" , &l , &r) ;
if(l > r)
swap(l , r) ;
update(l , r , i , 1 , n , 1) ;
}
query(1 , n , 1) ;
printf("%d\n" , Ans(n)) ;
}
return 0 ;
}
Hdu 4514
(1)"1 x y c",代表 把区间 [x,y] 上的值全部加c
(2)"2 x y c",代表 把区间 [x,y] 上的值全部乘以c
(3)"3 x y c" 代表 把区间 [x,y]上的值全部赋值为c
(4)"4 x y p" 代表 求区间 [x,y] 上值的p次方和1<=p<=3
const int Max_N = 100008 ;
const int Mod = 10007 ;
void ADD(int &x , int y){
x = ( x + y ) % Mod ;
}
struct Node{
int L , R ;
int sum[4];
int mult , add ;
int Len(){
return R - L + 1 ;
}
int Mid(){
return (L + R) >> 1 ;
}
void Init(int l , int r){
L = l ;
R = r ;
sum[1] = sum[2] = sum[3] = 0 ;
mult = 1 ;
add = 0 ;
}
void DoMult(int x){
sum[1] = sum[1] * x % Mod ;
sum[2] = sum[2] * x % Mod * x % Mod ;
sum[3] = sum[3] * x % Mod * x % Mod * x % Mod ;
mult = mult * x % Mod ;
add = add * x % Mod ;
}
void DoAdd(int x){
ADD(sum[3] , 3 * x * sum[2] % Mod) ;
ADD(sum[3] , 3 * x * x % Mod * sum[1]) ;
ADD(sum[3] , x * x % Mod * x % Mod * Len()) ;
ADD(sum[2] , sum[1] * 2 * x % Mod) ;
ADD(sum[2] , x * x % Mod * Len() % Mod) ;
ADD(sum[1] , x * Len() % Mod) ;
ADD(add , x) ;
}
} ;
Node seg[Max_N << 2] ;
void push_up(int root){
for(int i = 1 ; i <= 3 ; i++){
seg[root].sum[i] = (seg[root<<1].sum[i] + seg[root<<1|1].sum[i]) % Mod ;
}
}
void push_down(int root){
seg[root<<1].DoMult(seg[root].mult) ;
seg[root<<1].DoAdd(seg[root].add) ;
seg[root<<1|1].DoMult(seg[root].mult) ;
seg[root<<1|1].DoAdd(seg[root].add) ;
seg[root].mult = 1 ;
seg[root].add = 0 ;
}
void make_tree(int root , int L , int R){
seg[root].Init(L , R) ;
if(L == R)
return ;
int mid = (L + R) >> 1 ;
make_tree(root<<1 , L , mid) ;
make_tree(root<<1|1 , mid+1 , R) ;
push_up(root) ;
}
void update(int root , int L , int R , int _mult , int _add){
if(seg[root].L == L && seg[root].R == R){
seg[root].DoMult(_mult) ;
seg[root].DoAdd(_add) ;
return ;
}
push_down(root) ;
int mid = seg[root].Mid() ;
if(R <= mid)
update(root<<1 , L , R , _mult , _add) ;
else if(L > mid)
update(root<<1|1 , L , R , _mult , _add) ;
else{
update(root<<1 , L , mid , _mult , _add) ;
update(root<<1|1 , mid+1 , R , _mult , _add) ;
}
push_up(root) ;
}
int query(int root , int L , int R , int type){
if(seg[root].L == L && seg[root].R == R)
return seg[root].sum[type] ;
push_down(root) ;
int mid = seg[root].Mid() ;
int ans = 0 ;
if(R <= mid)
return query(root<<1 , L , R , type) ;
else if(L > mid)
return query(root<<1|1 , L , R , type) ;
else
return (query(root<<1 , L , mid , type) + query(root<<1|1 , mid+1 , R , type) ) % Mod;
}
int main(){
int n , m , k , l , r , c;
while(scanf("%d%d" ,&n ,&m)){
if(n == 0 && m == 0)
break ;
make_tree(1 , 1 , n) ;
while(m--){
scanf("%d%d%d%d" ,&k , &l , &r , &c) ;
if(k == 1)
update(1 , l , r , 1 , c) ;
else if(k == 2)
update(1 , l , r , c , 0) ;
else if(k == 3)
update(1 , l , r , 0 , c) ;
else
printf("%d\n" ,query(1 , l , r , c)) ;
}
}
return 0 ;
}
HDU 4288 给出一个有序集合,3种操作。插入一个数,删除一个数,都保证序列有序。以及求和 , 其中求和是将下标%5==3的所有数求和
const int Max_N = 100008 ;
int sum[Max_N<<2] ;
LL ans[Max_N<<2][5] ;
int x[Max_N] , query[Max_N] ;
char opt[Max_N][8] ;
void up(int t){
for(int i = 0 ; i < 5 ; i++)
ans[t][i] = ans[t<<1][i] + ans[t<<1|1][(i-sum[t<<1]%5 + 5)%5] ;
}
void make(int L , int R , int t){
memset(ans[t] , 0 , sizeof(ans[t])) ;
sum[t] = 0 ;
if(L == R) return ;
int M = (L + R) >> 1 ;
make(L , M , t<<1) ;
make(M+1 , R ,t<<1|1) ;
}
void update(int i , int g , int L , int R , int t){
sum[t] += (g==0? -1 : 1) ;
if(L == R){
ans[t][0] = (LL)(g*x[i]) ;
return ;
}
int M = (L + R) >> 1 ;
if(i <= M) update(i , g , L , M , t<<1) ;
else update(i , g , M+1 ,R , t<<1|1) ;
up(t) ;
}
int main(){
int i , n , t , pos ;
while(scanf("%d" ,&n) != EOF){
t = 0 ;
for(i = 1 ; i <= n ; i++){
scanf("%s" , opt[i]) ;
if(opt[i][0] == 'a' || opt[i][0] == 'd'){
scanf("%d" ,&query[i]) ;
x[t++] = query[i] ;
}
}
sort(x , x+t) ;
t = unique(x , x + t) - x ;
make(0 , t-1 , 1) ;
for(i = 1 ; i <= n ; i++){
if(opt[i][0] == 's') printf("%I64d\n" ,ans[1][2]) ;
else{
pos = lower_bound(x , x+t , query[i]) - x ;
if(opt[i][0] == 'a') update(pos , 1 , 0 , t-1 , 1) ;
else update(pos , 0 , 0 , t-1 , 1) ;
}
}
}
return 0 ;
}
给n个数,两种操作1:U a b 更新第a个为b (从0开始)2: Q a ,b 查询 a,b之间LCIS(最长连续递增子序列)的长度。
const int maxn = 100008 ;
int lmax[maxn<<2] , rmax[maxn<<2] , amax[maxn<<2] ;
int x[maxn] ;
void up(int t , int L , int R){
lmax[t] = lmax[t<<1] ;
rmax[t] = rmax[t<<1|1] ;
amax[t] = max(amax[t<<1] , amax[t<<1|1]) ;
int M = (L + R) >> 1 ;
if(x[M] < x[M+1]){
if(lmax[t] == M - L + 1) lmax[t] += lmax[t<<1|1] ;
if(rmax[t] == R - M) rmax[t] += rmax[t<<1] ;
amax[t] = max(amax[t] , rmax[t<<1] + lmax[t<<1|1]) ;
}
}
void make(int L , int R , int t){
if(L == R){
lmax[t] = rmax[t] = amax[t] = 1 ;
return ;
}
int M = (L + R) >> 1 ;
make(L , M , t<<1) ;
make(M+1, R , t<<1|1) ;
up(t , L , R) ;
}
void update(int i , int L , int R , int t){
if(L == R) return ;
int M = (L + R) >> 1 ;
if(i <= M) update(i , L , M , t<<1) ;
else update(i , M+1 , R , t<<1|1) ;
up(t , L , R) ;
}
int ask(int l , int r , int L , int R , int t){
if(l <= L && R <= r) return amax[t] ;
int M = (L + R) >> 1 ;
if(r <= M) return ask(l , r , L , M , t<<1) ;
if(l > M) return ask(l , r , M+1 , R , t<<1|1) ;
int s = max( ask(l , r , L , M , t<<1) , ask(l , r , M+1 , R , t<<1|1) ) ;
if(x[M] < x[M+1])
s = max(s , min(rmax[t<<1] , M-l+1) + min(lmax[t<<1|1] , r-M) ) ;
return s ;
}
int main(){
int i , n , t , m , id , a , b ;
char s[2] ;
cin>>t ;
while(t--){
scanf("%d%d" ,&n ,&m) ;
for(i = 1 ; i <= n ; i++) scanf("%d" ,&x[i]) ;
make(1 , n , 1) ;
id = 0 ;
while(m--){
scanf("%s%d%d" ,s , &a , &b) ;
if(s[0] == 'U'){
x[++a] = b ;
update(a , 1 , n , 1) ;
}
else{
a++ , b++ ;
printf("%d\n" , ask(a , b , 1 , n , 1)) ;
}
}
}
return 0 ;
}
给n个数,两种操作1:U a b c 更新[a , b] + c , 2: Q a ,b 查询 a,b之间LCIS(最长连续递增子序列)的长度。
const int maxn = 100008 ;
int lmax[maxn<<2] , rmax[maxn<<2] , amax[maxn<<2] ;
int x[maxn] , add[maxn<<2] , lx[maxn<<2] , rx[maxn<<2] ;
void up(int t , int L , int R){
lx[t] = lx[t<<1] ;
rx[t] = rx[t<<1|1] ;
lmax[t] = lmax[t<<1] ;
rmax[t] = rmax[t<<1|1] ;
amax[t] = max(amax[t<<1] , amax[t<<1|1]) ;
int M = (L + R) >> 1 ;
if(rx[t<<1] < lx[t<<1|1]){
if(lmax[t] == M - L + 1) lmax[t] += lmax[t<<1|1] ;
if(rmax[t] == R - M) rmax[t] += rmax[t<<1] ;
amax[t] = max(amax[t] , rmax[t<<1] + lmax[t<<1|1]) ;
}
}
void down(int t){
if(add[t]){
add[t<<1] += add[t] ;
add[t<<1|1] += add[t] ;
lx[t<<1] += add[t] ;
rx[t<<1] += add[t] ;
lx[t<<1|1] += add[t] ;
rx[t<<1|1] += add[t] ;
add[t] = 0 ;
}
}
void make(int L , int R , int t){
add[t] = 0 ;
if(L == R){
lmax[t] = rmax[t] = amax[t] = 1 ;
lx[t] = x[L] ;
rx[t] = x[L] ;
return ;
}
int M = (L + R) >> 1 ;
make(L , M , t<<1) ;
make(M+1, R , t<<1|1) ;
up(t , L , R) ;
}
void update(int l , int r , int a , int L , int R , int t){
if(l <= L && R <= r){
add[t] += a ;
lx[t] += a ;
rx[t] += a ;
return ;
}
down(t) ;
int M = (L + R) >> 1 ;
if(l <= M) update(l ,r , a , L , M , t<<1) ;
if(r > M) update(l ,r , a , M+1 , R , t<<1|1) ;
up(t , L , R) ;
}
int ask(int l , int r , int L , int R , int t){
if(l <= L && R <= r) return amax[t] ;
int M = (L + R) >> 1 ;
if(r <= M) return ask(l , r , L , M , t<<1) ;
if(l > M) return ask(l , r , M+1 , R , t<<1|1) ;
int s = max( ask(l , r , L , M , t<<1) , ask(l , r , M+1 , R , t<<1|1) ) ;
if(rx[t<<1] < lx[t<<1|1])
s = max(s , min(rmax[t<<1] , M-l+1) + min(lmax[t<<1|1] , r-M) ) ;
return s ;
}
int main(){
int i , n , t , m , id , a , b , c , T = 1 ;
char s[2] ;
cin>>t ;
while(t--){
scanf("%d%d" ,&n ,&m) ;
printf("Case #%d:\n" ,T++) ;
for(i = 1 ; i <= n ; i++) scanf("%d" ,&x[i]) ;
make(1 , n , 1) ;
id = 0 ;
while(m--){
scanf("%s" ,s) ;
if(s[0] == 'a'){
scanf("%d%d%d" ,&a ,&b ,&c) ;
update(a , b ,c , 1 ,n , 1) ;
}
else{
scanf("%d%d" ,&a ,&b) ;
printf("%d\n" , ask(a , b , 1 , n , 1)) ;
}
}
}
return 0 ;
}
0 l r表示查询区间[l,r]的最长的连续的1的个数,1 l r表示将区间[l,r]所有的数异或1(0->1 ,1->0)
const int maxn = 100008 ;
int preb[maxn<<2] , sufb[maxn<<2] , mxb[maxn<<2] ;
int prew[maxn<<2] , sufw[maxn<<2] , mxw[maxn<<2] ;
int color[maxn<<2] ;
void up(int t , int L , int R){
int M = (L + R) >> 1 ;
preb[t] = preb[t<<1] ;
sufb[t] = sufb[t<<1|1] ;
if(preb[t] == M-L+1) preb[t] += preb[t<<1|1] ;
if(sufb[t] == R-M) sufb[t] += sufb[t<<1] ;
prew[t] = prew[t<<1] ;
sufw[t] = sufw[t<<1|1] ;
if(prew[t] == M-L+1) prew[t] += prew[t<<1|1] ;
if(sufw[t] == R-M) sufw[t] += sufw[t<<1] ;
mxb[t] = max(mxb[t<<1] , mxb[t<<1|1]) ;
mxb[t] = max(mxb[t] , sufb[t<<1] + preb[t<<1|1]) ;
mxw[t] = max(mxw[t<<1] , mxw[t<<1|1]) ;
mxw[t] = max(mxw[t] , sufw[t<<1] + prew[t<<1|1]) ;
}
void change(int t){
swap(preb[t] , prew[t]) ;
swap(sufb[t] , sufw[t]) ;
swap(mxb[t] , mxw[t]) ;
}
void down(int t){
if(color[t]){
change(t<<1) ; change(t<<1|1) ;
color[t<<1] ^= 1 ;
color[t<<1|1] ^= 1 ;
color[t] = 0 ;
}
}
void make(int L , int R , int t){
color[t] = 0 ;
if(L == R){
int x ; scanf("%d" ,&x) ;
if(x == 1){
preb[t] = sufb[t] = mxb[t] = 1 ;
prew[t] = sufw[t] = mxw[t] = 0 ;
}
else{
preb[t] = sufb[t] = mxb[t] = 0 ;
prew[t] = sufw[t] = mxw[t] = 1 ;
}
return ;
}
int M = (L + R) >> 1 ;
make(L , M , t<<1) ;
make(M+1 , R , t<<1|1) ;
up(t , L , R) ;
}
void update(int l , int r , int L , int R , int t){
if(l <= L && R <= r){
change(t) ;
color[t] ^= 1 ;
return ;
}
down(t) ;
int M = (L + R) >> 1 ;
if(l <= M) update(l , r , L , M , t<<1) ;
if(r > M) update(l , r , M+1 , R , t<<1|1) ;
up(t , L , R) ;
}
int ask(int l , int r , int L , int R , int t){
if(l <= L && R <= r) return mxb[t] ;
down(t) ;
int M = (L + R) >> 1 ;
if(r <= M) return ask(l , r , L , M , t<<1) ;
if(l > M) return ask(l , r , M+1 , R , t<<1|1) ;
int s = max( ask(l , r , L , M , t<<1) , ask(l , r , M+1 , R , t<<1|1) ) ;
s = max(s , min(sufb[t<<1] , M-l+1) + min(preb[t<<1|1] , r-M) ) ;
return s ;
}
int main(){
int n , i , m , k , a , b ;
while(scanf("%d" ,&n) != EOF){
make(1 , n , 1) ;
scanf("%d" ,&m) ;
while(m--){
scanf("%d%d%d" ,&k , &a ,&b) ;
if(k) update(a , b , 1 , n , 1) ;
else printf("%d\n" , ask(a , b , 1 , n , 1)) ;
}
}
return 0 ;
}
在墙上贴海报[L, R], 海报可以互相覆盖,问最后可以看见几张不同的海报(离散化)
const int maxn = 10008 ;
int color[maxn<<4] ;
set<int> st ;
void down(int t){
if(color[t] != -1){
color[t<<1] = color[t<<1|1] = color[t] ;
color[t] = -1 ;
}
}
void update(int l , int r , int c , int L , int R , int t){
if(l <= L && R <= r){
color[t] = c ;
return ;
}
down(t) ;
int M = (L + R) >> 1 ;
if(l <= M) update(l , r , c , L , M , t<<1) ;
if(r > M) update(l , r , c , M+1, R , t<<1|1) ;
}
int sum ;
void query(int L , int R , int t){
if(color[t] != -1){
if(st.find(color[t]) == st.end()){
sum++ ;
st.insert(color[t]) ;
}
return ;
}
if(L == R) return ;
int M = (L + R) >> 1 ;
query(L , M , t<<1) ;
query(M+1 , R , t<<1|1) ;
}
int x[maxn<<2] , li[maxn] , ri[maxn] ;
int main(){
int t , n , m , i , k , l , r ;
cin>>t ;
while(t--){
scanf("%d" ,&n) ;
memset(color , -1 , sizeof(color)) ;
k = 0 ;
for(i = 1 ; i <= n ; i++){
scanf("%d%d" ,&li[i] , &ri[i]) ;
x[k++] = li[i] ;
x[k++] = ri[i] ;
}
sort(x , x+k) ;
k = unique(x , x+k) - x ;
for(i = k-1 ; i > 0 ; i--){
if(x[i] != x[i-1] + 1) x[k++] = x[i-1] + 1 ;
}
sort(x , x+k) ;
for(i = 1 ; i <= n ; i++){
l = lower_bound(x , x+k , li[i]) - x ;
r = lower_bound(x , x+k , ri[i]) - x ;
update(l , r , i , 0 , k-1 , 1) ;
}
st.clear() ; sum = 0 ;
query(0 , k-1 , 1) ;
printf("%d\n" , sum) ;
}
return 0 ;
}
n小球,初始时,所有的小球为黑色,然后就给出N次染色,每次染色是对[l ,r]全部染成white或black,最后要求出最长的white,给出其起点和终点球的编号。(离散化)
const int maxn = 2008 ;
int color[maxn<<4] ;
void down(int t){
if(color[t] != -1){
color[t<<1] = color[t<<1|1] = color[t] ;
color[t] = -1 ;
}
}
void make(int L , int R , int t){
color[t] = -1 ;
if(L == R){
color[t] = 0 ;
return ;
}
int M = (L + R) >> 1 ;
make(L , M , t<<1) ;
make(M+1 , R , t<<1|1) ;
}
void update(int l , int r , int c , int L , int R , int t){
if(l <= L && R <= r){
color[t] = c ;
return ;
}
down(t) ;
int M = (L + R) >> 1 ;
if(l <= M) update(l , r , c , L , M , t<<1) ;
if(r > M) update(l , r , c , M+1, R , t<<1|1) ;
}
int vis[maxn<<2] ;
void query(int L , int R , int t){
if(color[t] == 1){
for(int i = L ; i <= R ; i++) vis[i] = 1 ;
return ;
}
if(L == R) return ;
if(color[t] == -1){
int M = (L + R) >> 1 ;
query(L , M , t<<1) ;
query(M+1 , R , t<<1|1) ;
}
}
int x[maxn<<2] , li[maxn] , ri[maxn] , co[maxn];
int main(){
int n , i ,j , k , l , r , st , ed ;
char s[2] ;;
while(cin>>n){
k = 0 ;
for(i = 1 ; i <= n ; i++){
scanf("%d%d%s" ,&li[i] , &ri[i] , s) ;
x[k++] = li[i] ;
x[k++] = ri[i] ;
if(s[0] == 'w') co[i] = 1 ;
else co[i] = 0 ;
}
sort(x , x+k) ;
k = unique(x , x+k) - x ;
for(i = k-1 ; i > 0 ; i--){
if(x[i] != x[i-1] + 1) x[k++] = x[i-1] + 1 ;
}
sort(x , x+k) ;
make(0 , k-1 , 1) ;
for(i = 1 ; i <= n ; i++){
l = lower_bound(x , x+k , li[i]) - x ;
r = lower_bound(x , x+k , ri[i]) - x ;
update(l , r , co[i] , 0 , k-1 , 1) ;
}
memset(vis , 0 , sizeof(vis)) ;
query(0 , k-1 , 1) ;
st = -1 ; ed = -2 ;
x[k] = x[k-1] + 1 ;
for(i = 0 ; i < k ; i++){
if(vis[i]){
for(j = i ; j < k && vis[j] ; j++) ;
j-- ;
if(ed - st < x[j+1]-1 - x[i]){
st = x[i] ;
ed = x[j+1] - 1 ;
}
i = j ;
}
}
if(st == -1) puts("Oh, my god") ;
else printf("%d %d\n" , st , ed) ;
}
return 0 ;
}
给出一棵树,做 M 次操作,每次要么将一棵子树上每个结点的布尔值取反,要么查询一棵子树上布尔值为 true 的个数
先 dfs 将树转化成一个序列(求出每个结点的先序遍历值,以及它的所有子节点中的最大先序遍历值,以这两个值作为该结点在序列上的区间左右端点),然后用线段树维护,区间修改/区间查询,非常经典了
const int maxn = 100008 ;
vector<int> g[maxn] ;
int lock , sd[maxn] , td[maxn] ;
void dfs(int u){
sd[u] = ++lock ;
for(int i = 0 ; i < g[u].size() ; i++){
dfs(g[u][i]) ;
}
td[u] = lock ;
}
int sum[maxn<<2] , color[maxn<<2] ;
void down(int t , int L , int R){
if(color[t]){
color[t<<1] ^= 1 ;
color[t<<1|1] ^= 1 ;
color[t] = 0 ;
int M = (L + R) >> 1 ;
sum[t<<1] = (M-L+1) - sum[t<<1] ;
sum[t<<1|1] = (R-M) - sum[t<<1|1] ;
}
}
void up(int t){
sum[t] = sum[t<<1] + sum[t<<1|1] ;
}
void update(int l , int r , int L , int R , int t){
if(l <= L && R <= r){
sum[t] = (R-L+1) - sum[t] ;
color[t] ^= 1 ;
return ;
}
down(t , L , R) ;
int M = (L + R) >> 1 ;
if(l <= M) update(l , r , L , M , t<<1) ;
if(r > M) update(l , r , M+1 , R , t<<1|1) ;
up(t) ;
}
int ask(int l , int r , int L , int R , int t){
if(l <= L && R <= r) return sum[t] ;
down(t , L , R) ;
int s = 0 , M = (L + R) >> 1 ;
if(l <= M) s += ask(l , r , L , M , t<<1) ;
if(r > M) s += ask(l , r , M+1 , R , t<<1|1) ;
return s ;
}
int main(){
int n , m , i , x ;
char s[2] ;
while(cin>>n>>m){
for(i = 1 ; i <= n ; i++) g[i].clear() ;
for(i = 2 ; i <= n ; i++){
scanf("%d" ,&x) ;
g[x].push_back(i) ;
}
lock = 0 ;
dfs(1) ;
memset(sum , 0 , sizeof(sum)) ;
memset(color , 0 , sizeof(color)) ;
while(m--){
scanf("%s%d" ,s ,&i) ;
if(s[0] == 'o') update(sd[i],td[i],1,n,1) ;
else printf("%d\n" , ask(sd[i],td[i],1,n,1)) ;
}
puts("") ;
}
return 0 ;
}