日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/3 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 牛客练习赛73 D 离别(线段树+右端点排序离线查询) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

??途毩曎?3 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 离别(线段树+右端点排序离线查询)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。