欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

牛客练习赛73 D 离别(线段树+右端点排序离线查询)

发布时间:2023/12/3 51 豆豆
生活随笔 收集整理的这篇文章主要介绍了 牛客练习赛73 D 离别(线段树+右端点排序离线查询) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

牛客练习赛73 D 离别


思路: 对于每一个固定的右端点i,我们都找到一个区间(l,r)使得区间中的点为左端点时 里面最大的的种数为k。 这个可以用队列或者vector来维护。

然后我们对于q个查询,安装r从小到大排序。
开始遍历,把now点更新到q.r点,每次更新l【now】-r【now】这个区间的数都加1,使得 从1到r 点 做为右端点的(l,r)区间 全部更新,然后我们查询(q.l,q.r)中的区间和是多少 就是答案了。 因为当 右端点 i<q.l 的时候,他更新的(l,r) 区间必然是小于q.l的,那剩下的右端的i 全部都是在(q.l,q.r)中,既查询(q.l,q.r)就是答案。

#include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #include <bitset> #define INF 0x3f3f3f3f3f3f3f3f #define inf 0x3f3f3f3f #define FILL(a,b) (memset(a,b,sizeof(a))) #define re register #define lson rt<<1 #define rson rt<<1|1 #define lowbit(a) ((a)&-(a)) #define ios std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0); #define fi first #define rep(i,n) for(int i=0;(i)<(n);i++) #define rep1(i,n) for(int i=1;(i)<=(n);i++) #define se secondusing namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll> pii; const ll mod=20000311; const ll N =3e5+10; const double eps = 1e-5; //const double pi=acos(-1); ll qk(ll a,ll b){ll ans=1;while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans; }struct p{int l,r;ll sum,lazy; }s[N*4]; struct node{int l,r,id;bool operator<(const node &M) const{return r<M.r;} }a[N]; ll n,q,k; queue<int> p[N]; ll ans[N]; ll ls[N],rs[N]; ll b[N]; void up(int rt){s[rt].sum=s[lson].sum+s[rson].sum; } void down(int rt){if(s[rt].lazy){s[lson].sum+=(s[lson].r-s[lson].l+1)*s[rt].lazy;s[rson].sum+=(s[rson].r-s[rson].l+1)*s[rt].lazy;s[lson].lazy+=s[rt].lazy;s[rson].lazy+=s[rt].lazy;s[rt].lazy=0;}return; } void build(int rt,int l,int r) {s[rt].l=l,s[rt].r=r;s[rt].sum=0;s[rt].lazy=0;if(l==r) return;int mid=(l+r)>>1;build(lson,l,mid);build(rson,mid+1,r); } void add(int rt,int L,int R,int v){if(s[rt].l>=L&&s[rt].r<=R){s[rt].sum+=(s[rt].r-s[rt].l+1)*v;s[rt].lazy+=v;return;}down(rt);int mid=(s[rt].l+s[rt].r)>>1;if(mid>=L) add(lson,L,R,v);if(mid<R) add(rson,L,R,v);up(rt); } ll q1(int rt,int L,int R){if(s[rt].l>=L&&s[rt].r<=R){return s[rt].sum;}down(rt);int mid=(s[rt].l+s[rt].r)>>1;ll ans=0;if(mid>=L) ans+=q1(lson,L,R);if(mid<R) ans+=q1(rson,L,R);up(rt);return ans; } void sovle(){cin>>n>>q>>k;for(int i=1;i<=n;i++) cin>>b[i];int nowl=1,nowr=0;for(int i=1;i<=n;i++){p[b[i]].push(i);if(p[b[i]].size()>k) {int t=p[b[i]].front();p[b[i]].pop();nowl=max(t+1,nowl);}if(p[b[i]].size()==k) {nowr=max(nowr,p[b[i]].front());}ls[i]=nowl,rs[i]=nowr;// cout<<ls[i]<<" "<<rs[i]<<endl;}for(int i=1;i<=q;i++) {cin>>a[i].l>>a[i].r;a[i].id=i;}build(1,1,n);sort(a+1,a+1+q);int now=0;for(int i=1;i<=q;i++){while(now<a[i].r) {now++;if(ls[now]<=rs[now]) add(1,ls[now],rs[now],1);//cout<<q1(1,1,1)<<endl;}ans[a[i].id]=q1(1,a[i].l,a[i].r);}//cout<<q1(1,1,1)<<endl;for(int i=1;i<=q;i++) cout<<ans[i]<<endl; } int main() {iosint t=1;//cin>>t;while(t--) sovle();return 0; }

总结

以上是生活随笔为你收集整理的牛客练习赛73 D 离别(线段树+右端点排序离线查询)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。