acm_119士兵杀敌3

来源:互联网 发布:星星知多少 编辑:程序博客网 时间:2024/06/04 18:43

士兵杀敌(三)

时间限制:2000 ms  内存限制:65535KB
难度:5
描述

南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果。

所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少。

现在,请你写一个程序,帮小工回答南将军每次的询问吧。

注意,南将军可能询问很多次。

输入
只有一组测试数据
第一行是两个整数N,Q,其中N表示士兵的总数。Q表示南将军询问的次数。(1
随后的一行有N个整数Vi(0<=Vi<100000000),分别表示每个人的杀敌数。
再之后的Q行,每行有两个正正数m,n,表示南将军询问的是第m号士兵到第n号士兵。
输出
对于每次询问,输出第m号士兵到第n号士兵之间所有士兵杀敌数的最大值与最小值的差。
样例输入
5 21 2 6 9 31 22 4
样例输出
17
来源
经典改编
上传者
张云聪
这道题比较有意义,我使用了线段树,伪ST算法(主要是还没理解ST算法的含义就开始动手) ST算法实现
下面放代码
import java.util.Scanner;

//线段树的一种实现方式 TL

public class SoldierKillEnemy3V1 {
    int[][]tree; // tree[n][0]存子节点中最小的树 类推
    intsize;

    publicstatic void main(String[] args) {
      SoldierKillEnemy3V1 main = new SoldierKillEnemy3V1();
      main.solution();
    }

    public voidsolution() {
      Scanner in = new Scanner(System.in);
      size = in.nextInt();
      int cmds = in.nextInt();
      tree = new int[size * 4 + 1][2];
      init();

      for (int i = 1; i <= size; i++) {
          Update(i,in.nextInt());
      }
      int start = 0;
      int end = 0;
      for (int i = 1; i <= cmds; i++) {
          start =in.nextInt();
          end =in.nextInt();
         System.out.println(QueryMax(start, end) - QueryMin(start,end));
            
    }

    public voidinit() {
      for (int i = 0; i < tree.length; i++) {
          tree[i][0] =Integer.MAX_VALUE;
          tree[i][1] =Integer.MIN_VALUE;
      }
    }

    //在这条线段中的n节点 插入权值value;
    public voidUpdate(int n, int value) {
      Update(1, 1, size, n, value);
    }

    private voidUpdate(int index, int left, int right, int n, int value) {
      tree[index][0] = Math.min(tree[index][0], value);
      tree[index][1] = Math.max(tree[index][1], value);
      if (left == right) {
         return;
      } else {
          int mid =(left + right) >> 1;
          if (mid>= n) {

             Update(index<< 1, left, mid, n, value);
          } else{
             Update(index<< 1 | 1, mid + 1, right, n, value);
          }
      }
    }

    public intQueryMax(int start, int end) {
      return Query(start, end, true);
    }

    public intQueryMin(int start, int end) {
      return Query(start, end, false);
    }

    private intQuery(int start, int end, boolean ismax) {
      return Query(1, 1, size, start, end, ismax);
    }

    private intQuery(int index, int left, int right, int start, int end,
          booleanismax) {
      if (left >= start && right <= end) {
          int reval =ismax ? tree[index][1] : tree[index][0];
//         System.out
//               .println("leaf:" + left + " " + right + " reval:"+ reval);
          returnreval;
      }
      int reval = ismax ? Integer.MIN_VALUE : Integer.MAX_VALUE;
      int mid = (left + right) >> 1;
      if (mid >= start && left <= end) {
          reval =ismax ? Math.max(reval,
                Query(index<< 1, left, mid, start, end, ismax))
                :Math.min(reval,
                      Query(index<< 1, left, mid, start, end, ismax));
      }
      if (mid < end && right >= start) {
          reval =ismax ? Math.max(reval,
                Query(index<< 1 | 1, mid+1,right, start, end, ismax))
                :Math.min(reval,
                      Query(index<< 1 | 1, mid+1,right, start, end, ismax));
      }
//      System.out.println("node:" + left + " " + right +" reval:" + reval);
      return reval;
    }

}
之前做士兵杀敌1,2的原因 所以我上来也优先考虑了线段树,我更换了节点定义,每个节点存储了子树中的最小值和最大值,最后结果TL掉了

import java.util.Scanner;


//ST算法的实现方式 TL
public class SoldierKillEnemy3V2 {
    int[][][]tree; // tree[n][i][0]第i个节点后2^i个节点中的最小数
    //tree[n][i][1]第i个节点后2^i个节点中的最大数
    intsize;

    publicstatic void main(String[] args) {
      SoldierKillEnemy3V2 main = new SoldierKillEnemy3V2();
      main.solution();
    }

    public voidsolution() {
       Scanner in =new Scanner(System.in);
       size =in.nextInt();
       int cmds =in.nextInt();
       tree = newint[size+1][(int)(Math.log(size)/Math.log(2) + 1)][2];

       for (int i =1; i <= size; i++) {
         tree[i][0][0] = tree[i][0][1]= in.nextInt();
       }
       int curIndex= 1;
       int preSize= 1;
       int curSize= 2;
      while(curSize <= size){
          for(int i =1; i <(size-curSize+1) ; i++ ){
              tree[i][curIndex][0] =Math.min(tree[i][curIndex-1][0],tree[i+preSize][curIndex-1][0]);
              tree[i][curIndex][1] =Math.max(tree[i][curIndex-1][1],tree[i+preSize][curIndex-1][1]);         
          }
         curIndex++;
          preSize =curSize;
          curSize=curSize <<1;
       }
      
       int start =0;
       int end =0;
       for (int i =1; i <= cmds; i++) {
          start =in.nextInt();
          end =in.nextInt();
         System.out.println(QueryMax(start, end) - QueryMin(start,end));
            
    }


    public intQueryMax(int start, int end) {
       returnQuery(start, end, true);
    }

    public intQueryMin(int start, int end) {
       returnQuery(start, end, false);
    }

    private intQuery(int start, int end, boolean ismax) {
       int len =end - start+1;
       if(len ==1){
          returnismax?tree[start][0][1]:tree[start][0][0];
       }
       int exp =(int)(Math.log(len)/Math.log(2));
       int curSize=(int)Math.pow(2, exp);
      
       if(curSize>= len){
          returnismax?tree[start][exp][1]:tree[start][exp][0];
       }else{
          int tempval=ismax?tree[start][exp][1]:tree[start][exp][0];
          tempval =ismax?Math.max(tempval, Query(start+curSize, end, ismax)):
            Math.min(tempval, Query(start+curSize, end, ismax));
          returntempval;
       }
    }
}

     在参考了评论区的建议,我去看了下st树之后简单实现的,但是由于没有理解所以实现的有问题,最后也是TL的
最后是AC的
import java.util.Scanner;


//ST算法的实现方式
public class SoldierKillEnemy3V3 {
    int[][][]tree; // tree[n][i][0]第i个节点后2^i个节点中的最小数
    //tree[n][i][1]第i个节点后2^i个节点中的最大数
    intsize;

    publicstatic void main(String[] args) {
      SoldierKillEnemy3V3 main = new SoldierKillEnemy3V3();
      main.solution();
    }

    public voidsolution() {
       Scanner in =new Scanner(System.in);
       size =in.nextInt();
       int cmds =in.nextInt();
       int exp=(int)( Math.log(size)/Math.log(2) );
       tree = newint[size+1][exp + 1][2];

       for (int i =1; i <= size; i++) {
         tree[i][0][0] = tree[i][0][1]= in.nextInt();
       }
       int curIndex= 1;
       int preSize= 1;
       int curSize= 2;
      while(curSize <= size){
          for(int i =1; i <(size-curSize+1) ; i++ ){
              tree[i][curIndex][0] =Math.min(tree[i][curIndex-1][0],tree[i+preSize][curIndex-1][0]);
              tree[i][curIndex][1] =Math.max(tree[i][curIndex-1][1],tree[i+preSize][curIndex-1][1]);         
          }
         curIndex++;
          preSize =curSize;
          curSize=curSize <<1;
       }
       for(inti=1;i<=exp;i++){
          int tempmax=size-(1<<i)+1;
          for(intj=1;j<=tempmax;j++){
            
           tree[j][i][1]=Math.max(tree[j][i-1][1],tree[j+(1<<(i-1))][i-1][1]);
           tree[j][i][0]=Math.min(tree[j][i-1][0],tree[j+(1<<(i-1))][i-1][0]);
          }
       }
       int start =0;
       int end =0;
       for (int i =1; i <= cmds; i++) {
          start =in.nextInt();
          end =in.nextInt();
          int len =(int)(Math.log(end - start+1)/Math.log(2.0));
         System.out.println(Math.max(tree[start][len][1],tree[end-(1<<len)+1][len][1])-Math.min(tree[start][len][0],tree[end-(1<<len)+1][len][0]));
            
    }
}
这个版本和最优代码的结构一模一样,但是时间和空间消耗奇大务必,这个至今还没有理解


下面放系统给出的最优代码

   #include
#include
#include
#define max(a,b) a>b?a:b
#define min(a,b) a
const int N=100005;
int n,Q,c[N],a,b,k;
int dp_max[20][N]; //20不一定是唯一的。需要计算log(N)/log(2)
int dp_min[20][N];

//用来从输入流中获取一个数字
inline int Input()
{
int res=0,f=1,c;
while(!isdigit(c = getchar()) && c!='-');
c=='-' ? f=0 : res=c-'0';
while(isdigit(c = getchar()))
res = res*10 + c-'0';
return f ? res : -res;
}

void Init()
{
  //初始化St的输入数据
for(int i=1;i<=n;i++)
dp_max[0][i] = dp_min[0][i] = c[i];

//这里是生成稀疏矩阵
for(int j=1;j<20;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
{
dp_max[j][i] =max(dp_max[j-1][i],dp_max[j-1][i+(1<<(j-1))]);
dp_min[j][i] =min(dp_min[j-1][i],dp_min[j-1][i+(1<<(j-1))]);
}
}

int Get_Max(int a,int b)
{
k = (int)(log(b-a+1)/log(2.0));
return max(dp_max[k][a],dp_max[k][b-(1<<k)+1]);
}
int Get_Min(int a,int b)
{
return min(dp_min[k][a],dp_min[k][b-(1<<k)+1]);
}

int main()
{
    //读入数据
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++)
c[i] = Input();

Init();

while(Q--)
{
a = Input();
b = Input();
printf("%d\n",Get_Max(a,b)-Get_Min(a,b));
}

return 0;
}

   感觉解决方案一模一样,但是时间和空间消耗就不是一个数量级的  暂时想不懂

0 0
原创粉丝点击