hdu 5575 Discover Water Tank 数据结构xjb维护

Problem Description
A lot of frogs are living in a water tank, but none of them know exactly how much water are there.

The water tank has an infinite height, but with a narrow bottom. The length of the tank is N, and the width is only 1.

Now N−1 boards has divided the tank into N parts, each with an 1×1 bottom. Boards may have different heights. Water cannot flow through the boards, but can run freely if the water level is higher, following the basic physical rules.

The Frog King wants to know more details of the tank, so he sent someone to choose M positions and find whether there’s water at that position.

For example, each time he’ll choose(x,y), checking the xth part of the tank(1≤x≤N), counting from left to right, and find whether there’s water at height (y+0.5).

Now the King gets M results, but he finds some of them might be wrong. The King wants to find out the maximum possible number of the correct results.

Input
First line contains an integer T, which indicates the number of test cases.

Every test case begins with two integers N and M, which is the numbers of tanks and numbers of results.

The second line of each test case contains N−1 integers, h1, h2, ⋯, hN−1, and hi indicates the height of ith board’s height.

Then M lines follow, the ith line, formated as ‘x y z’, indicates ith result. z is 0 if there is no water at height (y+0.5) in xth tank, otherwise z is 1.

⋅ 1≤T≤100.

⋅ For 90% data, 1≤N≤1000 and 1≤M≤2000

⋅ for 100% data, 1≤N≤105 and 1≤M≤2⋅105.

⋅ 1≤hi≤109 for all 1≤i≤N−1.

⋅ for every result, 1≤x≤N, 1≤y≤109 and z is either 0 or 1.

Output
For every test case, you should output “Case #x: y”,where x indicates the case number and counts from 1, and y is the maximum possible number of the correct results.

Sample Input

2
3 4
3 4
1 3 1
2 1 0
2 2 0
3 3 1
2 2
2
1 2 0
1 2 1

Sample Output

Case #1: 3
Case #2: 1
Hint

In the first sample case, if the 1-st condition is true, then there’s water at height 3.5 in the first part. The water will run over the board with height 3, so the water level in the second part should also be the same as the first part, which contradicts the 2-nd and 3-rd observation.

题意:有一个水罐车,长为n宽为1,无限高,现在在里面插入n-1个板子,把它分成n个底为1×1的块,有m个条件,x,y,z,表示如果第x个块里高为y+0.5的地方有水,那么z为1,没水,z为0。问这m个条件最多有多少个是同时正确的。如果水高于板子会溢出。
做法:可以看作是区间处理。
如果现在有两个区间q1,q2,a,b,c为三个板子,分布为
a q1 b q2 c;(b < a ,b < c)
如果已知q1的最大贡献,和q2的最大贡献,那么q1 和q2这两个区间的点的最大贡献
先处理水面没有超过c时,最大贡献就是q1的最大贡献加上q2的最大贡献,如果水面超过c但是没有超过b和a,那么先处理得到水面到达c-0.5的时候,q1,q2得到的贡献,,,然后从c到min(a,b)枚举水面高度,得到最大贡献,与前面的最大贡献比较得较大,就是q1,q2两个区间合起来最大贡献。
具体实现:保存每个区间的最大贡献和水面将要超过水面的时候可以得到的贡献,按板子的从低到高处理,处理第i个板子的时候,l为i板子左边第一个比它高的板子,r为右边第一个比它高的板子,那么可以把l,r合起来作为一个新区间。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+100;
int que[N],d[N],ml[N],mr[N],h[N];
int sum[2][N*4],lz[2][N*4];
int st[20][N],lg[N];
int n,m;
struct node{
    int pos,h,op;
    bool operator<(const node &p)const{
        if(pos != p.pos) return pos < p.pos;
        if(h != p.h) return h < p.h;
        return op < p.op;
    }
};

bool cmp(node a,node b){
    if(a.h != b.h) return a.h < b.h;
    if(a.op != b.op) a.op < b.op;
    return a.pos < b.pos;

}
node pt[N];
vector<node> vp[2][N];
vector<pair<int,int> > vh;

void pushdown(int op,int rt){
    if(lz[op][rt] != -1){
        lz[op][rt<<1] = 0;
        lz[op][rt<<1|1] = 0;
        sum[op][rt<<1|1] =0;
        sum[op][rt<<1] =0;
        lz[op][rt] = -1;
    }
}

void build(int op,int l,int r,int rt){
    lz[op][rt] = -1;
    if(l == r){
        sum[op][rt] = 0;
        return ;
    }
    int mid = l+r>>1;
    build(op,l,mid,rt<<1);
    build(op,mid+1,r,rt<<1|1);
    sum[op][rt] = sum[op][rt<<1]+sum[op][rt<<1|1];
}

void update(int op,int L,int R,int c,int l,int r,int rt){
    if(L <= l && R >= r){
        lz[op][rt] = c;
        sum[op][rt] = c;
        return ;
    }
    pushdown(op,rt);
    int mid = l+r>>1;
    if(mid >= L) update(op,L,R,c,l,mid,rt<<1);
    if(mid < R) update(op,L,R,c,mid+1,r,rt<<1|1);
    sum[op][rt] = sum[op][rt<<1]+sum[op][rt<<1|1];
}
int query(int op,int L,int R,int l,int r,int rt){
    if(L <= l && R >= r){
        return sum[op][rt];
    }
    pushdown(op,rt);
    int mid = l+r>>1;
    int ans = 0;
    if(mid >= L) ans += query(op,L,R,l,mid,rt<<1);
    if(mid < R) ans += query(op,L,R,mid+1,r,rt<<1|1);
    return ans;
}


void init(int n){
    int top = 0;
    que[0] =0;
    ml[0] = 0;
    ml[n] = 0;
    for(int i = 1;i < n;i ++){
        while(h[i] >= h[que[top]]) top --;
        ml[i] = que[top];
        que[++top] = i;
    }
    top = 0;
    que[0] = n;
    mr[n] = n;
    mr[0] = n;
    for(int i = n-1;i > 0;i --){
        while(h[i] > h[que[top]]) top --;
        mr[i] = que[top];
        que[++top] = i;
    }



    for(int i = 0;i <= n;i ++) st[0][i] = h[i];
    int lgn = lg[n];
    for(int i = 1;i <= lg[n];i ++){
        for(int j = 0;j <= n;j ++){
            if(j+(1<<i) > n+1) st[i][j] = -1;
            else st[i][j] = max(st[i-1][j],st[i-1][j+(1<<i-1)]);
        }
    }
}

int check(int l,int r){
    int lgn = lg[r-l+1];
    return max(st[lgn][l],st[lgn][r-(1<<lgn)+1]);

}

int main(){
    lg[1] = 0;
    int now = 2;
    for(int i = 2;i < N;i ++){
        if(i > now) lg[i] = lg[i-1]+1,now *= 2;
        else lg[i] = lg[i-1];
    }
    int T;
    cin >> T;
    for(int kase = 1;kase <= T;kase ++){
        scanf("%d %d",&n,&m);
        for(int i= 1;i < n;i ++) scanf("%d",&h[i]);
        h[0] = 1e9+7,h[n] = 1e9+7;
        init(n);
        memset(d,0,sizeof(d));
        for(int i = 1;i <= m;i ++){
            scanf("%d %d %d",&pt[i].pos,&pt[i].h,&pt[i].op);
            if(pt[i].op == 0){
                d[pt[i].pos] ++;
            }
        }
        sort(pt+1,pt+1+m);

        build(0,1,n,1);
        build(1,1,n,1);
        vh.clear();
        for(int i = 0;i < n;i ++) vh.push_back({h[i],i});
        sort(vh.begin(),vh.end());
        for(int i= 0;i <= n;i ++) vp[0][i].clear(),vp[1][i].clear();
        for(int i = 1;i <= m;i ++){
            int pos = pt[i].pos;
            if(pt[i].h < min(h[pos],h[pos-1])) continue;
            int L, R;
            int l = 0,r = pos;
            while(r - l > 1){
                int mid = l+r>>1;
                if(check(mid,pos-1) > pt[i].h) l = mid;
                else r = mid;
            }
            L = l;
            l = pos-1,r = n;
            while(r -l > 1){
                int mid = l+r>>1;
                if(check(pos,mid) > pt[i].h) r = mid;
                else l = mid;
            }
            R = r;
            if(h[L] <= h[R]){
                vp[1][L].push_back(pt[i]);
            }
            else{
                vp[0][R].push_back(pt[i]);
            }
        }
        for(int i = 0;i <= 1;i ++){
            for(int j =0;j < n;j ++) sort(vp[i][j].begin(),vp[i][j].end(),cmp);
        }
        int tmp = 1;
        for(int i = 1;i <= n;i ++){
            while(tmp <= m && pt[tmp].pos < i) tmp ++;
            int mn = min(h[i-1],h[i]);
            int now = d[i];
            int mx = now;
            while(tmp <= m && pt[tmp].pos == i && pt[tmp].h < mn){
                if(pt[tmp].op == 1) now ++;
                else now --;
                mx = max(mx,now);
                tmp ++;
            }
            update(0,i,i,mx,1,n,1);
            update(1,i,i,now,1,n,1);
        }
        for(int i =0;i < n;i ++) {
            int pos = vh[i].second;
            //cout << pos << ' '<< vp[0][pos].size() << ' '<< vp[1][pos].size() << endl;
            int L = ml[pos];
            int now,mx;
            if(L != pos){
                now =  query(1,L+1,pos,1,n,1);
                mx = query(0,L+1,pos,1,n,1);
                //cout <<pos << ' '<< now << endl;
                for(int j = 0;j < vp[0][pos].size();j ++){
                    if(vp[0][pos][j].op == 1) now ++;
                    else now --;
                    //cout << "!!" << vp[0][pos][j].op <<endl;
                    mx = max(mx,now);
                }
                update(0,L+1,pos,0,1,n,1);
                update(0,L+1,L+1,mx,1,n,1);
                update(1,L+1,pos,0,1,n,1);
                update(1,L+1,L+1,now,1,n,1);
                //cout << pos << ' ' <<L+1 << ' '<< mx << ' '<<now << endl;
            }
            int R = mr[pos];
            now = query(1,pos+1,R,1,n,1);
            mx = query(0,pos+1,R,1,n,1);
            for(int j = 0;j < vp[1][pos].size();j ++){
                if(vp[1][pos][j].op == 1) now ++;
                else now --;
                mx = max(mx,now);
            }
            update(0,pos+1,R,0,1,n,1);
            update(0,pos+1,pos+1,mx,1,n,1);
            update(1,pos+1,R,0,1,n,1);
            update(1,pos+1,pos+1,now,1,n,1);
            //cout <<pos << ' '<< R << ' '<<mx << ' '<< now << endl;
        }
        printf("Case #%d: %d\n",kase,query(0,1,n,1,n,1));
    }


    return 0;
}
/*

6
6 7
3 4 7 10 3
1 5 0
2 5 0
3 5 0
2 6 1
4 8 1
5 9 1
6 9 1


555
4 2
5 5 1
4 2 1
4 4 0

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值