線段樹(單點修改,區間求和,區間最大)

(一)線段樹node

1.E - Lost Cowsios

 

N (2 <= N <= 8,000) cows have unique brands in the range 1..N. In a spectacular display of poor judgment, they visited the neighborhood 'watering hole' and drank a few too many beers before dinner. When it was time to line up for their evening meal, they did not line up in the required ascending numerical order of their brands. 

Regrettably, FJ does not have a way to sort them. Furthermore, he's not very good at observing problems. Instead of writing down each cow's brand, he determined a rather silly statistic: For each cow in line, he knows the number of cows that precede that cow in line that do, in fact, have smaller brands than that cow. 

Given this data, tell FJ the exact ordering of the cows. 

Input算法

* Line 1: A single integer, N 

* Lines 2..N: These N-1 lines describe the number of cows that precede a given cow in line and have brands smaller than that cow. Of course, no cows precede the first cow in line, so she is not listed. Line 2 of the input describes the number of preceding cows whose brands are smaller than the cow in slot #2; line 3 describes the number of preceding cows whose brands are smaller than the cow in slot #3; and so on. 

Output數組

* Lines 1..N: Each of the N lines of output tells the brand of a cow in line. Line #1 of the output tells the brand of the first cow in line; line 2 tells the brand of the second cow; and so on.

Sample Inputide

5
1
2
1
0

Sample Outputpost

2
4
5
3
1
解題思路:題意是已知每一個數字前面比她小的數的個數組成pre[]數組,讓咱們求他們的ans[]順序。
咱們能夠用暴力的方法來解決這道題:
思路是從後
往前處理pre數組,例如pre[]:0 1 2 1 0
pre[5]=0,表示ans[5]前面比她小的有0個,即他是最小的,所以ans[5]=1;同時ans數組中將再也不包括1
pre[4]=1,表示ans[4]前面比他小的有1個,即他是第二小,所以ans[4]=3;同時ans數組不在包括3
。。。
每次都是從剩下的編號裏找第pre[i]+1小,就是ans[i]
咱們解題用到三個數組,pre,ans,num[]數組記錄被處理過的數字,處理過就記爲-1,設置num的初始值就爲下標值
代碼:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=8010;

int pre[N],ans[N],num[N];//數組的第0個都不用,從1開始

int main()
{
    int n,i,j;
    scanf("%d",&n);
    pre[1]=0;
    for(i=2;i<=n;i++)
        scanf("%d",&pre[i]);
    for(i=1;i<=n;i++)
        num[i]=i;//給num賦初值
    for(i=n;i>=1;i--)
    {
        int k=0;
        for(j=1;j<=n;j++)
        {
            if(num[j]!=-1)
            {
                k++;
                if(k==pre[i]+1)//找到第pre[i]+1小的數
                {
                    ans[i]=num[j];//用ans記錄
                    num[j]=-1;//num數組標記
                    break;
                }
            }
        }
    }
    for(i=1;i<=n;i++)
        printf("%d\n",ans[i]);
    return 0;
}

 

用暴力若是數量級較大就不太適合了會TLE,那麼就引出咱們的線段樹測試

咱們用線斷樹實現的是建樹與修改和查詢。ui

代碼:this

#include<iostream>
#include<cstdio>
using namespace std;
const int  N=10000;
struct{
    int l,r,len;//len儲存這個區間的數字個數
}tree[4*N];
int pre[N],ans[N];
void BuildTree(int left,int right,int u)//建樹
{
    tree[u].l=left;
    tree[u].r=right;
    tree[u].len=right-left+1;
    if(left==right)
    {
        return;
    }
    BuildTree(left,(left+right)>>1,u<<1);//遞歸左子樹
    BuildTree(((left+right)>>1)+1,right,(u<<1)+1);//遞歸右子樹
}
int query(int u,int num)//維護+查詢
{
    tree[u].len--;//該區間長度-1
    if(tree[u].l==tree[u].r)
        return tree[u].l;//找到該點返回他的下標
    if(tree[u<<1].len<num)//若是左子樹的各數不夠,就查詢右子樹起第num-tree[u<<1].len的數下標
        return query((u<<1)+1,num-tree[u<<1].len);
    if(tree[u<<1].len>=num)//左子樹個數足夠,就找第num個數
        return query(u<<1,num);
}
int main()
{
    int n,i;
    scanf("%d",&n);
    pre[1]=0;
    for(i=2;i<=n;i++)
        scanf("%d",&pre[i]);
    BuildTree(1,n,1);//先建樹
    for(i=n;i>=1;i--)//從後往前找
        ans[i]=query(1,pre[i]+1);
    for(i=1;i<=n;i++)
        printf("%d\n",ans[i]);
    return 0;
}

 

2.G - A Simple Problem with Integersspa

You have N integers, A1A2, ... , 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 A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+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
解題思路:區間修改與求和(模板題)
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e5+10;
long long sum[N<<2],add[N<<2];
void push_up(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
//更新rt的子節點
void push_down(int rt,int m)
{
    if(add[rt])
    {
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=(m-(m>>1))*add[rt];
        sum[rt<<1|1]+=(m>>1)*add[rt];
        add[rt]=0;//取消標記
    }
}
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
void build(int l,int r,int rt)
{
    add[rt]=0;
    if(l==r)
    {
        scanf("%lld",&sum[rt]);
        return;
    }
    int mid=(r+l)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}
void update(int a,int b,long long c,int l,int r,int rt)
{
    if(a<=l&&b>=r)
    {
        sum[rt]+=(r-l+1)*c;
        add[rt]+=c;
        return;
    }
    push_down(rt,r-l+1);
    int mid=(l+r)>>1;
    if(a<=mid)
        update(a,b,c,lson);
    if(b>mid)
        update(a,b,c,rson);
    push_up(rt);//更新區間和
}
long long query(int a,int b,int l,int r,int rt)//區間求和
{
    if(a<=l&&b>=r)
        return sum[rt];
    push_down(rt,r-l+1);
    int mid=(l+r)>>1;
    long long ans=0;
    if(a<=mid)
        ans+=query(a,b,lson);
    if(b>mid)
        ans+=query(a,b,rson);
    return ans;
}
int main()
{
  int n,m;
  scanf("%d %d",&n,&m);
  build(1,n,1);
  while(m--)
  {
      char str[2];
      int a,b;
      long long c;
      scanf("%s",str);
      if(str[0]=='C')
      {
          scanf("%d%d%lld",&a,&b,&c);
          update(a,b,c,1,n,1);
      }
      else
      {
          scanf("%d%d",&a,&b);
          printf("%lld\n",query(a,b,1,n,1));
      }
  }
  return 0;
}
 

3.H - 敵兵佈陣

 
C國的死對頭A國這段時間正在進行軍事演習,因此C國間諜頭子Derek和他手下Tidy又開始忙乎了。A國在海岸線沿直線佈置了N個工兵營地,Derek和Tidy的任務就是要監視這些工兵營地的活動狀況。因爲採起了某種先進的監測手段,因此每一個工兵營地的人數C國都掌握的一清二楚,每一個工兵營地的人數都有可能發生變更,可能增長或減小若干人手,但這些都逃不過C國的監視。 
中央情報局要研究敵人究竟演習什麼戰術,因此Tidy要隨時向Derek彙報某一段連續的工兵營地一共有多少人,例如Derek問:「Tidy,立刻彙報第3個營地到第10個營地共有多少人!」Tidy就要立刻開始計算這一段的總人數並彙報。但敵兵營地的人數常常變更,而Derek每次詢問的段都不同,因此Tidy不得不每次都一個一個營地的去數,很快就精疲力盡了,Derek對Tidy的計算速度愈來愈不滿:"你個死肥仔,算得這麼慢,我炒你魷魚!」Tidy想:「你本身來算算看,這可真是一項累人的工做!我巴不得你炒我魷魚呢!」無奈之下,Tidy只好打電話向計算機專家Windbreaker求救,Windbreaker說:「死肥仔,叫你平時作多點acm題和看多點算法書,如今嚐到苦果了吧!」Tidy說:"我知錯了。。。"但Windbreaker已經掛掉電話了。Tidy很苦惱,這麼算他真的會崩潰的,聰明的讀者,你能寫個程序幫他完成這項工做嗎?不過若是你的程序效率不夠高的話,Tidy仍是會受到Derek的責罵的. 
Input
第一行一個整數T,表示有T組數據。 
每組數據第一行一個正整數N(N<=50000),表示敵人有N個工兵營地,接下來有N個正整數,第i個正整數ai表明第i個工兵營地裏開始時有ai我的(1<=ai<=50)。 
接下來每行有一條命令,命令有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 表示結束,這條命令在每組數據最後出現; 
每組數據最多有40000條命令 
Output
對第i組數據,首先輸出「Case i:」和回車, 
對於每一個Query詢問,輸出一個整數並回車,表示詢問的段中的總人數,這個數保持在int之內。 
Sample Input
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End 
Sample Output
Case 1:
6
33
59
解題思路:單點修改與區間求和,對於單點修改只要不斷的遞歸左右子樹找到他並改變他的值,而後向上傳遞修改區間的總和
#include<iostream>
#include<cstdio>
using namespace std;
const int N=100010;
int t,n,w[N];

struct node
{
    int l,r;
    int sum;
}tr[N*4];

void pushup(int u)
{
    tr[u].sum=tr[u*2].sum+tr[u*2+1].sum;
}

void build(int u,int l,int r)
{
    if(l==r)
        tr[u]={l,r,w[r]};
    else
    {
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u*2,l,mid),build(u*2+1,mid+1,r);
        pushup(u);
    }
}

int query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r)
        return tr[u].sum;
    int mid=tr[u].l+tr[u].r>>1;
    int sum=0;
    if(l<=mid)
        sum=query(u*2,l,r);
    if(r>mid)
        sum+=query(u*2+1,l,r);
    return sum;
}
void modify(int u,int x,int v)
{
    if(tr[u].l==tr[u].r)
        tr[u].sum+=v;
    else
    {
        int mid=(tr[u].l+tr[u].r)>>1;
        if(x<=mid)
            modify(u<<1,x,v);
        else
            modify(u*2+1,x,v);
        pushup(u);
    }
}
int main()
{
    int i,j;
    scanf("%d",&t);
    for(j=1;j<=t;j++)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
        }
        char str[10];
        int a,b;
        build(1,1,n);
        printf("Case %d:\n",j);
        while(scanf("%s",str)&&str[0]!='E')
        {
            scanf("%d%d",&a,&b);
            if(str[0]=='Q')
                printf("%d\n",query(1,a,b));
            else if(str[0]=='A')
                modify(1,a,b);
            else if(str[0]=='S')
                modify(1,a,-b);
        }
    }
    return 0;
}
 

 

4.I - Minimum Inversion Number

 

The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. 

For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following: 

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. 

InputThe input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1. 
OutputFor each case, output the minimum inversion number on a single line. 
Sample Input

10
1 3 6 9 0 8 5 7 4 2

Sample Output

16
解題思路:題意大概是求逆序數的最小值,有n個序列求他們的逆序數的最小值,這n個序列是經過不斷使第一個數放到末尾構成的
咱們能夠從中發現規律:每次將第一個數放到最後,其該序列的逆序數=上一個序列的逆序數+n-2*a[i]-1;由於以前有a[i]個逆序數,當放到後面後原來的逆序數變成了順序
而原來順序的變成了逆序,所以須要在原來序列逆序數的基礎上+(n-a[i]-1)-a[i],所以就是上面的式子。
以後咱們只需求出第一個序列的逆序數便可,而後經過一個循環就能夠找出最小的逆序數
代碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

const int N=5010;
struct node
{
    int l,r,sum;
}tr[4*N];

void push_up(int m)
{
    tr[m].sum=tr[m<<1].sum+tr[m<<1|1].sum;
}

void buildtree(int t,int l,int r)
{
    tr[t].l=l;
    tr[t].r=r;
    tr[t].sum=0;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    buildtree(t<<1,l,mid);
    buildtree(t<<1|1,mid+1,r);
}

int query(int t,int l,int r)
{
    if(tr[t].l>=l&&tr[t].r<=r)
        return tr[t].sum;
    int mid=(tr[t].l+tr[t].r)>>1;
    int ans=0;
    if(l<=mid)
        ans+=query(t<<1,l,r);
    if(r>mid)
        ans+=query(t<<1|1,l,r);
    return ans;
}

void update(int t,int id)
{
    if(tr[t].l==id&&tr[t].r==id)
    {
        tr[t].sum=1;
        return;
    }
    int mid=(tr[t].l+tr[t].r)>>1;
    if(id<=mid)
        update(t<<1,id);
    else
        update(t<<1|1,id);
    push_up(t);
}

int main()
{
    int n,i,j;
    int a[N];
    while(~scanf("%d",&n)&&n!=0)
    {
        buildtree(1,0,n-1);
        int sum=0;
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            sum+=query(1,a[i]+1,n-1);//找比a[i]大的數的個數的和
            update(1,a[i]);//將該值加入到線段樹中
        }
        int ans=sum;
        for(i=0;i<n;i++)
        {
            sum+=n-2*a[i]-1;
            ans=min(ans,sum);
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

5.J - Just a Hook

 
In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length. 



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. 

InputThe input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases. 
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. 
OutputFor each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example. 
Sample Input
1
10
2
1 5 2
5 9 3
Sample Output
Case 1: The total value of the hook is 24.
解題思路:區間修改與區間求和(lazy標記)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

const int N=100010;
struct node
{
    int sum,lazy;
}tr[4*N];

void push_up(int m)
{
    tr[m].sum=tr[m<<1].sum+tr[m<<1|1].sum;
}

void push_down(int t,int l,int r)
{
    int mid=(l+r)>>1;
    tr[t<<1].lazy=tr[t<<1|1].lazy=tr[t].lazy;
    tr[t<<1].sum=tr[t].lazy*(mid-l+1);
    tr[t<<1|1].sum=tr[t].lazy*(r-mid);
    tr[t].lazy=0;
}

void buildtree(int t,int l,int r)
{
    tr[t].lazy=0;
    if(l==r)
    {
        tr[t].sum=1;
        return;
    }
    int mid=(l+r)>>1;
    buildtree(t<<1,l,mid);
    buildtree(t<<1|1,mid+1,r);
    push_up(t);
}

void update(int t,int L,int R,int l,int r,int flag)
{
    if(L<=l&&r<=R)
    {
        tr[t].lazy=flag;
        tr[t].sum=(r-l+1)*flag;
        return;
    }
    if(tr[t].lazy)
        push_down(t,l,r);
    int mid=(l+r)>>1;
    if(L<=mid)
        update(t<<1,L,R,l,mid,flag);
    if(mid<R)
        update(t<<1|1,L,R,mid+1,r,flag);
    push_up(t);
}

long long query(int a,int b,int l,int r,int t)
{
    if(a<=l&&r<=b)
        return tr[t].sum;
    if(tr[t].lazy)
        push_down(t,l,r);
    int mid=(l+r)>>1;
    long long sum=0;
    if(a<=mid)
        sum+=query(a,b,l,mid,t<<1);
    if(b>mid)
        sum+=query(a,b,mid+1,r,t<<1|1);
    return sum;
}

int main()
{
    int t,i,j;
    scanf("%d",&t);
    for(i=1;i<=t;i++)
    {
        int n,q;
        scanf("%d%d",&n,&q);
        buildtree(1,1,n);
        while(q--)
        {
            int a,b,flag;
            scanf("%d%d%d",&a,&b,&flag);
            update(1,a,b,1,n,flag);
        }
        printf("Case %d: The total value of the hook is %d.\n",i,tr[1].sum);
    }
    return 0;
}
 

6.A - I Hate It

不少學校流行一種比較的習慣。老師們很喜歡詢問,從某某到某某當中,分數最高的是多少。 
這讓不少學生很反感。 

無論你喜不喜歡,如今須要你作的是,就是按照老師的要求,寫一個程序,模擬老師的詢問。固然,老師有時候須要更新某位同窗的成績。

Input本題目包含多組測試,請處理到文件結束。 
在每一個測試的第一行,有兩個正整數 N 和 M ( 0<N<=200000,0<M<5000 ),分別表明學生的數目和操做的數目。 
學生ID編號分別從1編到N。 
第二行包含N個整數,表明這N個學生的初始成績,其中第i個數表明ID爲i的學生的成績。 
接下來有M行。每一行有一個字符 C (只取'Q'或'U') ,和兩個正整數A,B。 
當C爲'Q'的時候,表示這是一條詢問操做,它詢問ID從A到B(包括A,B)的學生當中,成績最高的是多少。 
當C爲'U'的時候,表示這是一條更新操做,要求把ID爲A的學生的成績更改成B。 
Output對於每一次詢問操做,在一行裏面輸出最高成績。Sample Input

5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5

Sample Output

5
6
5
9

 解題思路:線段樹求區間最大與單點修改

 
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=200010;
struct node
{
    int l,r,ans;
}tr[N*4];
int pre[N];
void buildtree(int t,int l,int r)
{
    tr[t].l=l;
    tr[t].r=r;
    if(l==r)
    {
        tr[t].ans=pre[l];//葉子節點賦值
        return;
    }
    int mid=(l+r)>>1;
    buildtree(t<<1,l,mid);
    buildtree(t<<1|1,mid+1,r);
    tr[t].ans=max(tr[t<<1].ans,tr[t<<1|1].ans);//求出區間最大
}
void update(int t,int id,int key)//單點修改
{
    if(tr[t].l==id&&tr[t].r==id)
    {
        tr[t].ans=key;
        return;
    }
    int mid=(tr[t].l+tr[t].r)>>1;
    if(id<=mid)
        update(t<<1,id,key);
    else
        update(t<<1|1,id,key);
   tr[t].ans=max(tr[t<<1].ans,tr[t<<1|1].ans);//更新區間的最大值
}
int query(int t,int l,int r)//區間求最大值
{
    if(tr[t].l>=l&&tr[t].r<=r)
        return tr[t].ans;
    int mid=(tr[t].l+tr[t].r)>>1;
    int ans=-100;
    if(l<=mid)//找出左半邊的最大值
        ans=query(t<<1,l,r);
    if(r>mid)//將做半邊的最大值與右半邊的最大值比較
        ans=max(ans,query(t<<1|1,l,r));
    return ans;
}
int main()
{
    int n,m,i;
    while(~scanf("%d%d",&n,&m))
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d",&pre[i]);
        }
        buildtree(1,1,n);
        while(m--)
        {
            char s[2];
            int a,b;
            scanf("%s",&s);
            scanf("%d%d",&a,&b);
            if(s[0]=='Q')
            {
                printf("%d\n",query(1,a,b));
            }
            if(s[0]=='U')
            {
                update(1,a,b);
            }
        }
    }
    return 0;
}
 

7.B - Billboard

 
At the entrance to the university, there is a huge rectangular billboard of size h*w (h is its height and w is its width). The board is the place where all possible announcements are posted: nearest programming competitions, changes in the dining room menu, and other important information. 

On September 1, the billboard was empty. One by one, the announcements started being put on the billboard. 

Each announcement is a stripe of paper of unit height. More specifically, the i-th announcement is a rectangle of size 1 * wi. 

When someone puts a new announcement on the billboard, she would always choose the topmost possible position for the announcement. Among all possible topmost positions she would always choose the leftmost one. 

If there is no valid location for a new announcement, it is not put on the billboard (that's why some programming contests have no participants from this university). 

Given the sizes of the billboard and the announcements, your task is to find the numbers of rows in which the announcements are placed.

InputThere are multiple cases (no more than 40 cases). 

The first line of the input file contains three integer numbers, h, w, and n (1 <= h,w <= 10^9; 1 <= n <= 200,000) - the dimensions of the billboard and the number of announcements. 

Each of the next n lines contains an integer number wi (1 <= wi <= 10^9) - the width of i-th announcement.OutputFor each announcement (in the order they are given in the input file) output one number - the number of the row in which this announcement is placed. Rows are numbered from 1 to h, starting with the top row. If an announcement can't be put on the billboard, output "-1" for this announcement.Sample Input
3 5 5
2
4
3
3
3
Sample Output
1
2
1
3
-1
代碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=200010;
int maxx[N*4];
int h,w,n;

void push_up(int m)
{
    maxx[m]=max(maxx[m<<1],maxx[m<<1|1]);
}

void build(int t,int l,int r)
{
    if(l==r)
    {
        maxx[t]=w;
        return;
    }
    int mid=(l+r)>>1;
    build(t<<1,l,mid);
    build(t<<1|1,mid+1,r);
    push_up(t);
}
int update(int t,int val,int l,int r)
{
    if(val>maxx[t])
        return -1;
    if(l==r)
    {
        if(val<=maxx[t])
        {
            maxx[t]-=val;
            return l;
        }
        else
            return -1;
    }
    int mid=(l+r)>>1;
    int flag=-1;
    flag=update(t<<1,val,l,mid);
    if(flag<0)
        flag=update(t<<1|1,val,mid+1,r);
    push_up(t);
    return flag;
}
int main()
{
    int i,j;
    while(scanf("%d%d%d",&h,&w,&n)!=EOF)
    {
        if(h>n)
            h=n;
        build(1,1,h);
        int val;
        int k;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&val);
            printf("%d\n",update(1,val,1,h));
        }
    }
    return 0;
}
 

 

總結:lazy標記線段樹須要增強,區間修改操做的不熟練須要增強。
相關文章
相關標籤/搜索