zoukankan      html  css  js  c++  java
  • [火星补锅] siano 神奇的线段树

    前言:

    本来以为很难打的,没想到主干一次就打对了,然而把输入的b和d弄混了,这sb错误调了两个小时。。。

    解析:

    神奇的线段树。注意到有一个性质,无论怎么割草,生长速度快的一定不会比生长速度慢的矮。因此可以先排个序,然后就可以用线段树维护了。
    首先维护区间的sum,这个很显然。
    然后会发现一个问题,每次割草时,不知道从哪里开始割。这时可以运用线段树上二分的思想,维护一个区间max,每次只要查询区间中第一个大于上限的位置即可。
    还有区间赋值和区间加的标记,这个就是细节问题了。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=500000+10;
    #define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
    #define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = gc();} while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })
    char buf[1 << 20], *p1, *p2;
    int n,m;
    ll sum[maxn];
    ll b,d,last,ans;
    int a[maxn];
    struct Segment_tree{
    	ll sum,lazyfz,max,lazyadd;
    }tree[maxn<<2];
    bool cmp(int x,int y){
    	return x<y;
    }
    void build(int rt,int l,int r){
    	tree[rt].lazyfz=-1;
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	build(rt<<1,l,mid);
    	build(rt<<1|1,mid+1,r);
    }
    void update(int rt,int l,int r,ll x){
    	tree[rt].sum=x*(r-l+1);
    	tree[rt].max=x;
    	tree[rt].lazyfz=x;
    	tree[rt].lazyadd=0;
    }
    void updateadd(int rt,int l,int r,ll x){
    	tree[rt].sum+=x*(sum[r]-sum[l-1]);
    	tree[rt].max+=x*a[r];
    	tree[rt].lazyadd+=x;
    }
    void pushdown(int rt,int l,int r){
    	int mid=(l+r)>>1;
    	if(tree[rt].lazyfz!=-1){
    		update(rt<<1,l,mid,tree[rt].lazyfz);
    		update(rt<<1|1,mid+1,r,tree[rt].lazyfz);
    		tree[rt].lazyfz=-1;
    	}
    	if(tree[rt].lazyadd){
    		updateadd(rt<<1,l,mid,tree[rt].lazyadd);
    		updateadd(rt<<1|1,mid+1,r,tree[rt].lazyadd);
    		tree[rt].lazyadd=0;
    	}
    }
    void mm(ll x){
    	pushdown(1,1,n);
    	updateadd(1,1,n,x);
    }
    int query(int rt,int l,int r,int s,int t,ll x){//查找第一个大于x的数,如果没有,返回-1;
    	if(l==r) return tree[rt].max>x ? l : -1 ;
    	if(tree[rt].max<=x) return -1;
    	pushdown(rt,l,r);
    	int mid=(l+r)>>1;
    	if(t<=mid) return query(rt<<1,l,mid,s,t,x);
    	if(s>mid) return query(rt<<1|1,mid+1,r,s,t,x);
    	int res=query(rt<<1,l,mid,s,t,x);
    	if(res!=-1) return res;
    	return query(rt<<1|1,mid+1,r,s,t,x);
    }
    ll querysum(int rt,int l,int r,int s,int t){
    	if(s<=l&&r<=t) return tree[rt].sum;
    	int mid=(l+r)>>1;
    	pushdown(rt,l,r);
    	if(t<=mid) return querysum(rt<<1,l,mid,s,t);
    	if(s>mid) return querysum(rt<<1|1,mid+1,r,s,t);
    	return querysum(rt<<1,l,mid,s,t)+querysum(rt<<1|1,mid+1,r,s,t);
    }
    void pushup(int rt){
    	tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
    	tree[rt].max=max(tree[rt<<1].max,tree[rt<<1|1].max);
    }
    void modify(int rt,int l,int r,int s,int t,ll x){
    	if(s<=l&&r<=t){
    		update(rt,l,r,x);
    		return;
    	}
    	int mid=(l+r)>>1;
    	pushdown(rt,l,r);
    	if(s<=mid) modify(rt<<1,l,mid,s,t,x);
    	if(t>mid) modify(rt<<1|1,mid+1,r,s,t,x);
    	pushup(rt);
    }
    void Solve(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    	sort(a+1,a+n+1,cmp);
    	for(int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];
    	build(1,1,n);
    	for(int i=1;i<=m;++i){
    		scanf("%lld%lld",&b,&d);
    		mm(b-last);
    		last=b;
    		int x=query(1,1,n,1,n,d);
    		if(x!=-1){
    			ans=querysum(1,1,n,x,n);
    			ans-=d*(n-x+1);
    			modify(1,1,n,x,n,d);
    		}else ans=0;
    		printf("%lld
    ",ans);
    	}
    }
    int main(){
    	Solve();
    	return 0;
    }
    
    
  • 相关阅读:
    python 随机字符串
    Ajax
    Django (Form)
    Django (项目)
    Django (二)
    Django (一)
    Django 学生管理系统
    地理坐标系 与 投影坐标系
    shapefile
    图表绘制工具--Matplotlib 3
  • 原文地址:https://www.cnblogs.com/wwcdcpyscc/p/13895515.html
Copyright © 2011-2022 走看看