codevs 2018 反病毒软件

一个求最大值和次大值的问题。

在更新的时候将两个子区间的最大次大值都算进去,排个序再装进去即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 800005
using namespace std;
struct tree
{
 int left,right;
 int value1,value2;
}node[maxn];
struct ans
{
 int a,b;
};
int n,q,father[maxn],type,x,y;
void build(int i,int left,int right)
{
 node[i].left=left;
 node[i].right=right;
 node[i].value1=0;
 node[i].value2=0;
 if (left==right)
 {
  father[left]=i;
  return;
 }
 else
 {
  int mid=(left+right)>>1;
  i=i<<1;
  build(i,left,mid);
  build(i+1,mid+1,right);
 }
}
void modify(int x)
{
 int fath=x>>1,a[5];
 int ls=fath<<1,rs=(fath<<1)+1;
 a[1]=node[ls].value1;
 a[2]=node[ls].value2;
 a[3]=node[rs].value1;
 a[4]=node[rs].value2;
 sort(a+1,a+5);
 node[fath].value1=a[4];
 node[fath].value2=a[3];
 if (fath==1) return;
 else modify(fath);
}
ans ask(int i,int l,int r)
{
 int left=node[i].left,right=node[i].right;
 int value1=node[i].value1,value2=node[i].value2;
 if ((left==l) && (right==r))
 {
  ans tk;
  tk.a=node[i].value1;
  tk.b=node[i].value2;
  return tk;
 }
 else
 {
  int mid=(left+right)>>1;
  if (r<=mid)
   return ask(i<<1,l,r);
  else if (l>=mid+1)
   return ask((i<<1)+1,l,r);
  else
  {
   ans tk,yk,rep;
   tk=ask(i<<1,l,mid);
   yk=ask((i<<1)+1,mid+1,r);
   int a[5];
   a[1]=tk.a;a[2]=tk.b;
   a[3]=yk.a;a[4]=yk.b;
   sort(a+1,a+5);
   rep.a=a[4];rep.b=a[3];
   return rep;
  }
 }
}
int main()
{
 scanf("%d%d",&n,&q);
 build(1,1,n);
 for (int i=1;i<=q;i++)
 {
  scanf("%d%d%d",&type,&x,&y);
  if (type==1)
  {
   node[father[x]].value1+=y;
   modify(father[x]);
  }
  else
  {
   ans k=ask(1,x,y);
   printf("%d\n",k.a-k.b);
  }
 }
 return 0;
}

你可能感兴趣的:(codevs 2018 反病毒软件)