随笔 - 97, 文章 - 22, 评论 - 81, 引用 - 0
数据加载中……

PKU 2777 Count Color

题目链接:http://poj.org/problem?id=2777
/*
题意:
    给定一个长度为N(N <= 100000)的数列Si,紧接着Q(Q <= 100000)条操作,操作
形式有两种:
1. "C A B C" 将A到B的数都染成C这种颜色。 
2. "P A B" 输出A和B之间不同颜色的数目。


解法:
线段树(染色问题)

思路:
    一看到数据量就可以首先确定是线段树了,经典的区间染色问题,涉及到区间的
更新和询问,和pku 3468 类似,巧妙运用lazy思想。就是每次更新区间段的时候延迟
更新,只是在完全覆盖的区间打上一个lazy标记。这题的询问是求区间段中不同颜色的
数量,因为颜色数不多只有30种,可以巧妙运用二进制位运算,用一个int就可以表示
当前区间段的颜色情况。比如1001表示有两种颜色,如果左子树的当前颜色情况是101
,而右子树的颜色情况是011,那么父亲的颜色情况就是两者的位或,这样就可以避免
掉重复的情况。
    再来谈谈lazy思想。做了这么多的线段树,应该总结一下,lazy是一个很经典的思
想。所谓lazy,就是懒惰,每次不想做太多,只要插入的区间完全覆盖了当前结点所管
理的区间就不再往下做了,在当前结点上打上一个lazy标记,然后直接返回。下次如果
遇到当前结点有lazy标记的话,直接传递给两个儿子,自己的标记清空。这样做肯定是
正确的。我们以染色为例,可以这样想,如果当前结点和它的子孙都有lazy标记的话,
必定是子孙的先标记,因为如果是自己先标记,那么在访问子孙的时候,必定会将自己
的标记下传给儿子,而自己的标记必定会清空,那么lazy标记也就不存在了。所以可以
肯定,当前的lazy标记必定覆盖了子孙的,所以直接下传即可,不需要做任何判断。当
然,这是染色问题,是直接赋值的,如果像pku 3468那样,每次是区间加和,则传递标
记的时候不能简单的赋值,必须累加,这是显而易见的。
*/
/*
lazy思想
    染色模型
        适合颜色数目较少(64以内)的区间染色问题。
        具体操作:
            1、对某个连续区间进行染色。
            2、询问某个连续区间的颜色情况(种类、数目等等)。
        适用题型:
            poj 2777 Count Color
            hdu 5023 A Corrupt Mayor's Performance Art
        结点存储
            颜色值的位或colorBit:每个颜色用2的幂来表示,颜色值表示分别为1、2、4、8,该区间有哪些颜色就可以用他们的或来表示
            延迟标记lazy:该段区间完全被染色成了lazy这种颜色,这里的lazy要么是2的幂,要么是0

        接口说明
            giveLazyToSon      传递延迟标记给两个子结点(调用子结点的updateByValue,并且lazy重置)
            updateByValue      通过某个颜色值更新当前结点信息(更新colorBit、lazy)
            updateFromSon      通过两个子结点更新当前结点信息(更新colorBit)
            mergeQuery         询问时用于对分割后的子结点进行合并用,不同情况实现不同

        调用说明
            建树:              调用静态函数   treeNode::segtree_build(1, 1, n);
            插入([x, y], val): 调用静态函数   treeNode::segtree_insert(1, 1, n, x, y, val);
            询问([x, y]):       调用静态函数   treeNode::segtree_query(1, 1, n, x, y, ans);

*/ 
#include <iostream>

using namespace std;

#define MAXN 131072
typedef int ValueType;


// 返回[l, r]和[x, y]两条线段是否相交
bool is_intersect(int l, int r, int x, int y) {
      return !(r < x || l > y);
}
// 返回[x, y]是否完全包含[l, r]
bool is_contain(int l, int r, int x, int y) {
      return x <= l && r <= y;
}

struct treeNode {
    ValueType lazy;
    ValueType colorBit;
      int pid;
      int len;

    treeNode() {
        reset(-1, 0);
    }
      void reset(int p, int _len) {
        pid = p;
        colorBit = 0;
        lazy = 0;
        len = _len;
    }
    int lson() { return pid << 1; }
    int rson() { return pid<<1|1; }

    void updateByValue(ValueType _val);
    void giveLazyToSon();
    void updateFromSon();

    // 询问的时候将结点合并后计入答案
    void mergeQuery(int p);

    // 建树 
    static void segtree_build(int p, int l, int r);
    // 插入线段[x, y]到[l, r]
    static void segtree_insert(int p, int l, int r, int x, int y, ValueType val);
    // 区间询问[x, y]上的信息
    static void segtree_query(int p, int l, int r, int x, int y, treeNode& ans);
};

/* 全局变量 
    nodes[MAXN*2] 存储所有静态线段树结点(动态开内存太费时间)
    totalNodes    存储结点数目
*/
treeNode nodes[MAXN*2];

void treeNode::updateByValue(ValueType _val) {
    lazy = _val;
    colorBit = _val;
}

void treeNode::giveLazyToSon() {
      if(lazy) {
        nodes[ lson() ].updateByValue(lazy);
        nodes[ rson() ].updateByValue(lazy);    
        lazy = 0;        
    }
}

void treeNode::updateFromSon() {
    colorBit = nodes[ lson() ].colorBit | nodes[ rson() ].colorBit;
}

void treeNode::mergeQuery(int p) {
    colorBit |= nodes[p].colorBit;
}

void treeNode::segtree_build(int p, int l, int r) {
    // 创建线段树结点的时候只需要知道该线段树结点管辖区间的长度,区间端点不用存,可以在递归的时候作为函数传参
    nodes[p].reset(p, r-l+1);
      if (l < r) {
            int mid = (l + r) >> 1;
            // 递归创建左右儿子结点
        treeNode::segtree_build(p<<1, l, mid);
        treeNode::segtree_build(p<<1|1, mid+1, r);
        nodes[p].updateFromSon();
    }
}

void treeNode::segtree_insert(int p, int l, int r, int x, int y, ValueType val) {
      if( !is_intersect(l, r, x, y) ) {
            return ;
      }
      if( is_contain(l, r, x, y) ) {
        nodes[p].updateByValue(val);
            return ;
    } 
    nodes[p].giveLazyToSon();
      int mid = (l + r) >> 1; 
    treeNode::segtree_insert(p<<1, l, mid, x, y, val);
    treeNode::segtree_insert(p<<1|1, mid+1, r, x, y, val);
    nodes[p].updateFromSon();
}

void treeNode::segtree_query(int p, int l, int r, int x, int y, treeNode& ans) {
      if( !is_intersect(l, r, x, y) ) {
            return ;
      }
      if( is_contain(l, r, x, y) ) {
            ans.mergeQuery(p);
            return;
    }
    nodes[p].giveLazyToSon();
      int mid = (l + r) >> 1; 
    treeNode::segtree_query(p<<1, l, mid, x, y, ans);
    treeNode::segtree_query(p<<1|1, mid+1, r, x, y, ans);
    nodes[p].updateFromSon();


int n, t, o;

int main() {
    int i;
    while( scanf("%d %d %d", &n, &t, &o) != EOF ) {
            treeNode::segtree_build(1, 1, n);
            for(i = 1; i <= n; i++) {
            treeNode::segtree_insert(1, 1, n, i, i, 1<<0);
            }
            while(o--) {
                  char str[10];
                  int x, y, z;

                  scanf("%s", str);
                  if(str[0] == 'C') {
                           scanf("%d %d %d", &x, &y, &z);
                           if(x > y) swap(x, y);
                           treeNode::segtree_insert(1, 1, n, x, y, 1<<(z-1) );
                  }else {
                           scanf("%d %d", &x, &y);
                           if(x > y) swap(x, y);
                 treeNode ans;
                 treeNode::segtree_query(1, 1, n, x, y, ans);
                 z = 0;
                          for(i = 0; i < t; i++) {
                                if( (1<<i) & ans.colorBit ) {
                        z ++;
                    }
                }
                printf("%d\n", z);
            }
        }
    }
    return 0;
}

/*
2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
*/

posted @ 2011-03-31 19:49 英雄哪里出来 阅读(1602) | 评论 (0)编辑 收藏

ZJU 3349 Special Subsequence

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3349

/*
题意:
    给定一个d(0 <= d <= 10^8)和(N <= 10^5)的数列,求最长的特殊子序列,
所谓特殊子序列就是相邻元素之间的绝对值之差小于等于d。

解法:
动态规划+线段树

思路:
    这题又是一个动态规划,状态转移方程很容易想到:
    dp[ val[i] ] = 1 + max( dp[ val[i] - d ]  dp[ val[i] + d ] )
dp[j] 表示以j为止的最长特殊子序列的值,这样就可以维护一个区间,每次
查询和当前数绝对值差小于等于d的数组成的区间,将最大值+1更新到当前数
对应的位置上,利用线段树每次更新和查询都是log(n)。
*/


#include 
<iostream>
#include 
<cstdio>
#include 
<cstring>
using namespace std;

#define maxn 600010

int n, d;
int val[maxn];

struct Tree {
    
int Max;
    
int son[2];

    
void clear() {
        son[
0= son[1= -1;
        Max 
= 0;
    }

}
T[maxn*4];
int tot;

int Max(int a, int b) {
    
return a > b ? a : b;
}

int Min(int a, int b) {
    
return a < b ? a : b;
}


void Query(int root, int nx, int ny, int l, int r, int& ans) {
    
if(nx > r || ny < l || root == -1 || T[root].Max <= ans)
        
return ;
    
if(nx <= l && r <= ny) {
        ans 
= Max(ans, T[root].Max);
        
return ;
    }

    
int mid = (l + r) >> 1;
    Query(T[root].son[
0], nx, ny, l, mid, ans);
    Query(T[root].son[
1], nx, ny, mid+1, r, ans);
}


void Insert(int& root, int nPos, int l, int r, int val) {
    
if(nPos < l || nPos > r)
        
return ;
    
if(root == -1{
        root 
= tot++;
        T[root].clear();
    }

    T[root].Max 
= Max(val, T[root].Max);

    
if(l == nPos && nPos == r) {
        
return ;
    }


    
int mid = (l + r) >> 1;
    Insert(T[root].son[
0], nPos, l, mid, val);
    Insert(T[root].son[
1], nPos, mid+1, r, val);
}


int main() {
    
int i;
    
int MMin, MMax;
    
while(scanf("%d %d"&n, &d) != EOF) {
        
for(i = 0; i < n; i++{
            scanf(
"%d"&val[i]);
            
if(i) {
                MMin 
= Min(MMin, val[i]);
                MMax 
= Max(MMax, val[i]);
            }
else {
                MMin 
= val[i];
                MMax 
= val[i];
            }

        }

        tot 
= 0;
        
int root = -1;
        
int ans = 1;

        
for(i = 0; i < n; i++{
            
int l = (val[i] - d) < MMin ? MMin : (val[i] - d);
            
int r = (val[i] + d) > MMax ? MMax : (val[i] + d);
            
int MM = 0;
            Query(root, l, r, MMin, MMax, MM);
            Insert(root, val[i], MMin, MMax, MM 
+ 1);
            
if(MM + 1 > ans)
                ans 
= MM + 1;
        }


        printf(
"%d\n", ans);
    }

    
return 0;
}

posted @ 2011-03-31 17:39 英雄哪里出来 阅读(1051) | 评论 (0)编辑 收藏

ZJU 2451 Minimizing maximizer

     摘要: 题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1451 /**//*题意:    有这样一个机器Maximizer,它的输入是N(N <= 50000)个1到N的数,输出最大的数。这个机器的工作原理是通过读入M(M <= 5...  阅读全文

posted @ 2011-03-31 16:12 英雄哪里出来 阅读(1525) | 评论 (0)编辑 收藏

HDU 2852 KiKi's K-Number

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2852
/*
题意:
    给出三种操作,
    0 在容器中插入一个数。
    1 在容器中删除一个数。
    2 求出容器中大于a的第k大元素。

解法:
二分+树状数组

思路:
    树状数组的特点就是对点更新,成段求和,而且常数非常小。原始
的树状数组只有两种操作,在某点插入一个数 和 求1到i的所有数的和。
这道题目一共有三种操作,但是实质上其实只有两种:插入和询问。插入
操作和删除操作可以视为一种,只不过一个是将标记+1,另一个是-1,而
插入的数对应于树状数组的下标,这样就可以在log(n)的时间内完成插入
和删除。求大于a的k大元素,可以通过二分枚举答案来完成,枚举的是当
前答案在树状数组中的位置,设为m,然后对v[a+1]  v[m]求和就是小
于等于m的数的个数,这一步可以用树状数组的求和操作来完成,然后根据
和k的比较来调整m的位置。询问的复杂度也是log(n)的。
*/


#include 
<iostream>

using namespace std;

#define maxn 100002
int C[maxn], n;

int lowbit(int x) {
    
return x & (-x);
}


void Add(int pos, int val) {
    
while(pos < maxn) {
        C[pos] 
+= val;
        pos 
+= lowbit(pos);
    }

}


int Sum(int pos) {
    
int S = 0;
    
while(pos >= 1{
        S 
+= C[pos];
        pos 
-= lowbit(pos);
    }

    
return S;
}


int find(int a, int k) {
    
int l = a + 1;
    
int r = maxn - 1;
    
int S = Sum(a);
    
int ans = maxn;

    
while(l <= r) {
        
int m = (l + r) >> 1;
        
int nS = Sum(m);
        
if(nS - S >= k) {
            r 
= m - 1;
            
if(m < ans)
                ans 
= m;
        }
else
            l 
= m + 1;
    }


    
return ans;
}



int main() {
    
int n;
    
int i;
    
while(scanf("%d"&n) != EOF) {
        
for(i = 1; i < maxn; i++)
            C[i] 
= 0;
        
while(n--{
            
int id, e, a, k;
            scanf(
"%d"&id);
            
if(id == 0{
                scanf(
"%d"&e);
                Add(e, 
1);
            }
else if(id == 1{
                scanf(
"%d"&e);
                
if(Sum(e) - Sum(e-1== 0)
                    printf(
"No Elment!\n");
                
else
                    Add(e, 
-1);
            }
else {
                scanf(
"%d %d"&a, &k);
                
int num = find(a, k);
                
if(num == maxn) {
                    printf(
"Not Find!\n");
                }
else
                    printf(
"%d\n", num);
            }

        }

    }

    
return 0;
}

posted @ 2011-03-31 13:10 英雄哪里出来 阅读(1426) | 评论 (0)编辑 收藏

PKU 2104 K-th Number

     摘要: 题目链接:http://poj.org/problem?id=2104 /**//*题意:    给出一个长度为N(N <= 100000)的数列,然后是一连串询问,询问数<= 50000,询问的格式是a, b, k,问[a, b]区间中的k小数。解法:二分+归并树+线段树思路:&nb...  阅读全文

posted @ 2011-03-31 11:33 英雄哪里出来 阅读(1382) | 评论 (0)编辑 收藏

HDU 3333 Turing Tree

     摘要: 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3333 /**//*题意:    给出一个长度为N(N <= 30000)的数列,然后是一连串询问,询问数<= 100000,问给定区间内不同数字的和。解法:离线算法+离散化+线段树思路:  &nbs...  阅读全文

posted @ 2011-03-30 22:52 英雄哪里出来 阅读(2549) | 评论 (0)编辑 收藏

HDU 1255 覆盖的面积

     摘要: 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255 /**//*题意:    给出N(N <= 1000)个矩形,求被覆盖2次以上的矩形面积并。解法:离散化+线段树思路:    类似于覆盖一次的矩形面积并问题,还是用线段树求解,首先我们将每...  阅读全文

posted @ 2011-03-30 19:58 英雄哪里出来 阅读(2447) | 评论 (1)编辑 收藏

HDU 3458 Rectangles Too!

     摘要: 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3458 /**//*题意:    给定n(1<= n <= 100000)个矩形,问最长的递增矩形序列。矩形A和BA = ((xA1 , yA1 ), (xA2...  阅读全文

posted @ 2011-03-30 17:05 英雄哪里出来 阅读(1149) | 评论 (0)编辑 收藏

ZJU 2859 Matrix Searching

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2859

/*
题意:
    给定一个n*n(n <= 300)的矩阵,然后是(T <= 10^6)次询问,每次询问某个子矩
阵中的最小值。

解法:
二维线段树 或者 二维RMQ

思路:
    一维线段树是一颗完全二叉树,那么二维线段树无疑就是一颗完全四叉树,换言
之,每个结点有四个儿子,这里为了空间不浪费,将所有结点记录在一个一维数组中
,每个结点的四个儿子采用编号的方式存储,在建树之前将每个结点的信息全部初始
化,初始化的时候需要注意的是每次将当前结点的四个儿子清空,然后判断它本身是
否是叶子结点,可以通过x和y区间端点是否重合来判断,最后再来生成四个儿子编号
,然后往下递归,递归结束后根据四个儿子的最小值更新当前的最小值。再来看询问
,和一维的情况类似,一维是对区间交,而二维则是对矩形交,如果询问的二维区间
和当前结点管理的二维区间没有交集,显然不可能有最小值,直接返回inf,否则如果
询问的二维区间完全包含了当前结点管理的二维区间,那么返回结点最小值。否则递
归当前结点的四个儿子,取最小值,回归到根节点就得到了询问区间的最值了。
    需要注意的是在建树的时候不要在叶子结点生成多余的儿子结点,这样内存会多
一倍,如果开得不够大有可能下标越界,开得太大有可能超内存。还有就是在二维线
段树的结点上信息会多了不少,能节省空间尽量节省,比如每个结点管理的区间端点
不可能很大,所以不需要int,short就足够了。
*/


#include 
<iostream>
#include 
<cstring>
#include 
<cstdio>

using namespace std;

#define maxn 310
#define inf  (1<<30)-1

struct Tree {
    
int Min;           // 当前结点区间最小值
    int son[4];        // 四个儿子在数组中的编号
    short x[2], y[2];  // 当前结点管理的二维区间
}
T[maxn*maxn*5];

int Tree_Id;

int n;
int mat[maxn][maxn];

void Build(int fat, int x0, int x1, int y0, int y1) {
    
int i;
    
for(i = 0; i < 4; i++{
        T[fat].son[i] 
= 0;
    }

    T[fat].x[
0= x0;  T[fat].x[1= x1;
    T[fat].y[
0= y0;  T[fat].y[1= y1;

    
if(x0 == x1 && y0 == y1) {
        T[fat].Min 
= mat[x0][y0];
        
return ;
    }

    
for(i = 0; i < 4; i++{
        T[fat].son[i] 
= Tree_Id++;
    }


    
int xmid = (x0 + x1) >> 1;
    
int ymid = (y0 + y1) >> 1;
    Build(T[fat].son[
0], x0, xmid,   y0, ymid);
    Build(T[fat].son[
1], x0, xmid,   (ymid<y1) ? ymid+1 : ymid, y1);
    Build(T[fat].son[
2], (xmid<x1) ? xmid+1 : xmid, x1, y0, ymid);
    Build(T[fat].son[
3], (xmid<x1) ? xmid+1 : xmid, x1, (ymid<y1) ? ymid+1 : ymid, y1);

    T[fat].Min 
= T[T[fat].son[0]].Min;
    
for(i = 1; i < 4; i++{
        
if(T[T[fat].son[i]].Min < T[fat].Min)
            T[fat].Min 
= T[T[fat].son[i]].Min;
    }

}


int Query(int fat, int x0, int x1, int y0, int y1) {
    
if(x0 > T[fat].x[1|| x1 < T[fat].x[0]
    
|| y0 > T[fat].y[1|| y1 < T[fat].y[0]) {
        
return inf;
    }


    
if(x0 <= T[fat].x[0&& T[fat].x[1<= x1
        
&& y0 <= T[fat].y[0&& T[fat].y[1<= y1) {
        
return T[fat].Min;
    }

    
int i;
    
int Min = inf;
    
for(i = 0; i < 4; i++{
        
int v = Query(T[fat].son[i], x0, x1, y0, y1);
        
if(v < Min)
            Min 
= v;
    }

    
return Min;
}


int main() {
    
int t;
    
int i, j;

    scanf(
"%d"&t);
    
while(t--{
        scanf(
"%d"&n);
        Tree_Id 
= 0;
        
for(i = 1; i <= n; i++{
            
for(j = 1; j <= n; j++{
                scanf(
"%d"&mat[i][j]);
            }

        }

        Tree_Id 
= 2;
        Build(
11, n, 1, n);

        
int m;
        scanf(
"%d"&m);

        
while(m--{
            
int r[2], c[2];
            scanf(
"%d %d %d %d"&r[0], &c[0], &r[1], &c[1]);
            printf(
"%d\n", Query(1, r[0], r[1], c[0], c[1]));
        }

    }

    
return 0;
}

posted @ 2011-03-30 13:07 英雄哪里出来 阅读(1384) | 评论 (0)编辑 收藏

ZJU 2706 Thermal Death of the Universe

     摘要: 题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2706 /**//*题意:    给定一个长度为N(N <= 30000)的数列Si,紧接着Q条区间处理,每一条处理的要求是将给定的区间内的数字替换成他们的平均值,替换时如果当前数列的总和比原先数列...  阅读全文

posted @ 2011-03-30 11:58 英雄哪里出来 阅读(1208) | 评论 (2)编辑 收藏

PKU 3468 A Simple Problem with Integers

     摘要: 题目链接:http://poj.org/problem?id=3468 /**//*题意:    给定一个长度为N(N <= 100000)的数列Si,紧接着Q条询问,询问格式如下:"C a b c" 表示对 Aa, Aa+1,  , Ab&...  阅读全文

posted @ 2011-03-30 11:16 英雄哪里出来 阅读(1292) | 评论 (0)编辑 收藏

PKU 1151 Atlantis

     摘要: 题目链接:http://poj.org/problem?id=1151 /**//*题意:    给定n(n <= 100)个矩形,求它们的面积并。解法:离散化+线段树 或者 离散化+FloodFill思路:    数据量很小,直接把浮点数离散成整点,然后暴力FloodF...  阅读全文

posted @ 2011-03-30 00:44 英雄哪里出来 阅读(1244) | 评论 (0)编辑 收藏

HDU 3265 Posters

     摘要: 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3265 /**//*题意:    给定N(N <= 50000)个中空的矩形纸片,求它们面积并。解法:离散化+线段树思路:    2010年宁波区域赛的题,就是矩形面积并的一个变形,转化很容易想到...  阅读全文

posted @ 2011-03-29 21:09 英雄哪里出来 阅读(1451) | 评论 (0)编辑 收藏

PKU 3368 Frequent values

     摘要:  题目链接:http://poj.org/problem?id=3368 /**//*题意:    给定一个长度为N(N <= 100000)的单调不降数列Si,然后是Q(Q <= 100000)条询问,问给定区间出现最多的数的次数。解法:离散化+线段树 或者 离散化+RMQ...  阅读全文

posted @ 2011-03-29 18:30 英雄哪里出来 阅读(1189) | 评论 (0)编辑 收藏

PKU 3264 Balanced Lineup

题目链接:http://poj.org/problem?id=3264
/*
题意:
    给定一个长度为N(N <= 50000)的数列Si,紧接着Q(1 <= Q <= 200000)条询问,
每次询问给出两个数字表示数列的区间下标,问该区间中最大数和最小数的差。

解法:
线段树 或者 RMQ

思路:
    线段树区间最值,维护一颗完全二叉树,每个结点保存两个值,表示该结点管理
的区间的最大值和最小值,比如1号为根结点,管理区间[1, n],每个结点p有左儿子
2*p和右儿子2*p+1,当区间两端点相同时为叶子结点,如果p管理的是[a,b]那么2*p则
管理区间[a, (a+b)/2],2*p+1管理区间[(a+b)/2+1, b],如此一来就可以通过递归,
将儿子的信息传递给父亲,直至根节点。
*/


#include 
<iostream>

using namespace std;

#define maxn 50010

struct Tree {
    
int Min, Max;
}
T[maxn*4];

int val[maxn];
typedef 
int Tree_Index;

void Build(int p, int l, int r) {
    
if(l == r) {
        T[p].Max 
= T[p].Min = val[l];
        
return ;
    }

    
int mid = (l + r) >> 1;
    Build(p
<<1, l, mid);
    Build(p
<<1|1, mid+1, r);
    T[p].Max 
= T[p<<1].Max > T[p<<1|1].Max ? T[p<<1].Max : T[p<<1|1].Max;
    T[p].Min 
= T[p<<1].Min < T[p<<1|1].Min ? T[p<<1].Min : T[p<<1|1].Min;
}


Tree_Index Query(
int p, int l, int r, int a, int b, bool bMin) {
    
if(l == a && b == r)
        
return p;
    
int mid = (l + r) >> 1;
    
if(b <= mid) {
        
return Query(p<<1, l, mid, a, b, bMin);
    }
else if(mid + 1 <= a) {
        
return Query(p<<1|1, mid+1, r, a, b, bMin);
    }
else {
        Tree_Index p1 
= Query(p<<1, l, mid, a, mid, bMin);
        Tree_Index p2 
= Query(p<<1|1, mid+1, r, mid+1, b, bMin);
        
if(bMin) {
            
return T[p1].Min < T[p2].Min ? p1 : p2;
        }
else {
            
return T[p1].Max > T[p2].Max ? p1 : p2;
        }

    }

}


int main() {
    
int n, m;
    
int i;
    
while(scanf("%d %d"&n, &m) != EOF) {
        
for(i = 1; i <= n; i++{
            scanf(
"%d"&val[i]);
        }

        Build(
11, n);
        
while(m--){
            
int x, y;
            scanf(
"%d %d"&x, &y);
            Tree_Index pMax 
= Query(11, n, x, y, false);
            Tree_Index pMin 
= Query(11, n, x, y, true);
            printf(
"%d\n", T[pMax].Max - T[pMin].Min);
        }

    }

    
return 0;
}

posted @ 2011-03-29 18:15 英雄哪里出来 阅读(1195) | 评论 (0)编辑 收藏

PKU 2452 Sticks Problem

     摘要: 题目链接:http://poj.org/problem?id=2452 /**//*题意:    给定一个长度为N(N <= 50000)的数列Si,要求找到Si和Sj(1 <= i < j <= N)使得所有的Sk(i < k...  阅读全文

posted @ 2011-03-29 18:05 英雄哪里出来 阅读(1540) | 评论 (0)编辑 收藏

仅列出标题
共3页: 1 2 3