首页 > 代码库 > uva 12356 Army Buddies 树状数组解法 树状数组求加和恰为k的最小项号 难度:1

uva 12356 Army Buddies 树状数组解法 树状数组求加和恰为k的最小项号 难度:1

Nlogonia is fighting a ruthless war against the neighboring country of Cubiconia. The Chief General of Nlogonia‘s Army decided to attack the enemy with a linear formation of soldiers, that would advance together until conquering the neighboring country. Before the battle, the Chief General ordered that each soldier in the attack line, besides protecting himself and attacking, should also protect his two (nearest) neighbors in the line, one to his left and one to his right. The Chief General told the soldiers that for each of them, his ``buddies" would be these two neighbors, if such neighbors existed (because the leftmost soldier does not have a left neighbor and the rightmost soldier does not have a right neighbor). The Chief General also told the soldiers that protecting their buddies was very important to prevent the attack line from being broken. So important that, if the left or right buddy of a soldier is killed, then the next living neighbor to the left or to the right of the soldier, respectively, should become his buddy.

The battle is fierce, and many soldiers in the attack line are being killed by fire shots, grenades and bombs. But following the Chief General‘s orders, immediately after knowing about losses in the attack line, the Army‘s information systems division has to inform the soldiers who their new buddies are.

You are given the number of soldiers in the attack line, and a sequence of loss reports. Each loss report describes a group of contiguous soldiers in the attack line that were just killed in the battle. Write a program that, for each loss report, prints the new buddies formed.

 

Input 

Each test case is described using several lines. The first input line contains two integers S and Brepresenting respectively the number of soldiers in the attack line, and the number of loss reports ( 1$ \le$B$ \le$S$ \le$105). Soldiers are identified by different integers from 1 to S, according to their positions in the attack line, being 1 the leftmost soldier and S the rightmost soldier. Each of the next B input lines describes a loss report using two integers L (left) and R (right), meaning that soldiers from L to R were killed ( 1$ \le$L$ \le$R$ \le$S). You may assume that until that moment those soldiers were alive and were just killed.

The last test case is followed by a line containing two zeros.

 

Output 

For each test case output B + 1 lines. In the i-th output line write the new buddies formed by removing from the attack line the soldiers that were just killed according to the i-th loss report. That is, for the loss report `L R‘, print the first surviving soldier to the left of L, and the first surviving soldier to the right of R. For each direction, print the character `*‘ (asterisk) if there is no surviving soldier in that direction. Print a line containing a single character `-‘ (hyphen) after each test case.

 

Sample Input 

 

1 11 110 42 56 91 110 105 11 10 0

 

Sample Output 

 

* *-1 61 10* 10* *-* 2-
这道题一开始想用线段树来做,然后改成了树状数组,结果发现就不应该用树状数组做,那个悬在超时边上
经验教训:不可以用dat[k]!=0判断第k位置的人没有被杀,这个值可能是比它小的人贡献的
思路: 每个位置都是1,被杀了就变成0,因为每个人只杀一次,所以顶多被杀10^5次,这个即使按人更新都可以承受,所以就干脆分开从L到R的闭区间的每个点杀了都更新成0;对于一整个区间,因为都是0,所以sum(0,i)(i属于区间中的下标)都是相等的;而左边的没被杀的人恰好是等于这个值的第一个序号,右边没被杀的人是等于这个值+1的第一个序号,用来求sum(0,i)当然是树状数组
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn=1e5+2;int s,b;int dat[maxn<<1];int lowbit(int k ){    return k&(-k);}void update(int k,int a){  if(k<0||dat[k]+a<0)return ;    while(k<=s){        dat[k]+=a;        k+=lowbit(k);    }}int query(int k){    int ans=0;    while(k>0){        ans+=dat[k];        k-=lowbit(k);    }
return ans;}int getk(int k){//找到和恰为k的第一个点,返回值小于等于n,大于等于1 if(k<0)return 0; int ans=0,cnt=0; for(int i=25;i>=0;i--){ ans+=(1<<i); if(ans>=s||cnt+dat[ans]>=k)ans-=(1<<i); else cnt+=dat[ans]; } return ans+1;}int main(){ while(scanf("%d%d",&s,&b)==2&&s&&b){ //for(int i=1;i<=s;i++)update(i,-1);这个不行
     memset(dat,0,sizeof(int)*2*n);    for(int i=1;i<=s;i++)update(i,1);//初始化    for(int i=0;i<b;i++){    int l,r;    scanf("%d%d",&l,&r);    for(int i=l;i<=r;i++)update(i,-1);//减人    int tmp=query(r);//查询这个区间前面剩余人数    int pos1=getk(tmp);//找到左端点    int pos2=getk(tmp+1);//找到右端点
       if(query(pos2)!=tmp+1)pos2++;//因为这个算法不会超过n,为了判断最后一个人是否存在    if(query(pos1)==0)putchar(‘*‘);   else printf("%d",pos1);    putchar(‘ ‘);    if(pos2>s)putchar(‘*‘);    else printf("%d",pos2);   putchar(‘\n‘);    }    puts("-");//分割case } return 0;}

  

uva 12356 Army Buddies 树状数组解法 树状数组求加和恰为k的最小项号 难度:1