当前位置: 代码迷 >> 综合 >> HDU 6521 Party(线段树+二分+思维贡献)*
  详细解决方案

HDU 6521 Party(线段树+二分+思维贡献)*

热度:23   发布时间:2023-11-15 11:22:26.0

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6521

题目大意

给定n和m个操作,

n代表序列长度,

每个操作给定一个区间,

代表把这个区间的人聚到一起,

其区间效率是这个区间中多少对人没有在之前的区间中

已经聚过.

题目分析 

线段树+思维转化,

我们可以对每个人,维护一个

数组代表其最远认识到右边的哪一个人,

比如如果区间1,4操作后,那么1最远可以认识到4,

考虑到相互性,我们只需要对每个人维护一端即可.

初始化每个人对应的就是他自己的位置.

更新不难,但查询有点困难,对于区间中数组值

大于右端点的,没有贡献,而在右端点之内的,产生与右端点之差的贡献,

我们无法通过普通的区间求和去表示这一关系.

考虑其数组值的单调性,不难发现我们定义的数组值始终是不减的,

那么我们就可以二分出最大的权重小于右端点的位置点,

有了这个点后就可以进行传统的区间更新了,

我们维护最大值和一个区间和,

注意懒惰标记的更新不是直接赋值而是直接取max,越大越好,

其他一些细节就是数据范围的问题了.

#include<bits/stdc++.h>
using namespace std;#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=5e5+10;
const int ub=1e6;
const int INF=-1e9;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
给定n和m个操作,
n代表序列长度,
每个操作给定一个区间,
代表把这个区间的人聚到一起,
其区间效率是这个区间中多少对人没有在之前的区间中
已经聚过.题目分析:
线段树+思维转化,
我们可以对每个人,维护一个
数组代表其最远认识到右边的哪一个人,
比如如果区间1,4操作后,那么1最远可以认识到4,
考虑到相互性,我们只需要对每个人维护一端即可.
初始化每个人对应的就是他自己的位置.
更新不难,但查询有点困难,对于区间中数组值
大于右端点的,没有贡献,而在右端点之内的,产生与右端点之差的贡献,
我们无法通过普通的区间求和去表示这一关系.
考虑其数组值的单调性,不难发现我们定义的数组值始终是不减的,
那么我们就可以二分出最大的权重小于右端点的位置点,
有了这个点后就可以进行传统的区间更新了,
我们维护最大值和一个区间和,
注意懒惰标记的更新不是直接赋值而是直接取max,越大越好,
其他一些细节就是数据范围的问题了.
*/
int rt[maxn],minv[maxn<<2],x,y;
int maxv[maxn<<2],lazy[maxn<<2];
ll sum[maxn<<2];
void build(lrt){lazy[rt]=0;if(l==r){sum[rt]=maxv[rt]=l;return ;}int mid=l+r>>1;build(lson),build(rson);maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(lrt){int mid=l+r>>1;if(lazy[rt]){lazy[rt<<1]=max(lazy[rt<<1],lazy[rt]);lazy[rt<<1|1]=max(lazy[rt<<1|1],lazy[rt]);maxv[rt<<1]=max(maxv[rt<<1],lazy[rt]);maxv[rt<<1|1]=max(maxv[rt<<1|1],lazy[rt]);sum[rt<<1]=1LL*(mid-l+1)*maxv[rt<<1];sum[rt<<1|1]=1LL*(r-mid)*maxv[rt<<1|1];lazy[rt]=0;}
}
int getpos(lrt,int p){pushdown(root);if(l==r) return maxv[rt];int mid=l+r>>1;if(p<=mid) return getpos(lson,p);else return getpos(rson,p);
}
void update(lrt,int L,int R,int v){if(L<=l&&r<=R){maxv[rt]=max(maxv[rt],v);sum[rt]=1LL*(r-l+1)*maxv[rt];lazy[rt]=max(lazy[rt],v);return;}pushdown(l,r,rt);int mid=l+r>>1;if(L<=mid) update(lson,L,R,v);if(mid<R) update(rson,L,R,v);maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}ll getsum(lrt,int L,int R){if(L<=l&&r<=R) return sum[rt];pushdown(l,r,rt);int mid=l+r>>1;ll ans=0;if(L<=mid) ans+=getsum(lson,L,R);if(mid<R) ans+=getsum(rson,L,R);maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);sum[rt]=sum[rt<<1]+sum[rt<<1|1];return ans;
}
int n,m;
int main(){while(scanf("%d%d",&n,&m)!=EOF){build(1,n,1);rep(i,0,m){scanf("%d%d",&x,&y);int l=1,r=n,p=0;while(l<=r){int mid=l+r>>1;if(getpos(1,n,1,mid)<y){p=mid;l=mid+1;}else{r=mid-1;}}p=min(p,y);if(x<=p){printf("%lld\n",1LL*(p-x+1)*y-getsum(1,n,1,x,p));update(1,n,1,x,p,y);}else{puts("0");}}}return 0;
}