牛客练习赛73D 离别
https://ac.nowcoder.com/acm/contest/9033/D
分析:这种类型的题目做法很固定
首先离线 设当前点为i 若以i为右端点 则合法的左端点一定是连续的一段 设为[l,r] 这个可以预处理出来
预处理的时候要注意 不能只考虑i的颜色 一定要和之前的颜色取max
询问的时候 区间修改区间求和 从小到大扫一遍则可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
typedef pair<int,int> plll;
const int N=3e5+10;
const int inf=0x3f3f3f3f;
const int mod=998244353;
struct node{
int l,r;
ll sum;
int lazy;
}tr[N<<2];
int n,q1,k;
queue<int> q[N];
int f[N],e[N];
int a[N];
struct Q{
int l,id;
}s[N];
vector<Q> num[N];
ll ans[N];
void build(int u,int l,int r){
if(l==r){
tr[u]={l,r,0,0};
}
else{
tr[u]={l,r};
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
}
}
void pushup(int u){
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void pushdown(int u){
int x=tr[u].lazy;
tr[u<<1].sum+=(tr[u<<1].r-tr[u<<1].l+1)*x,tr[u<<1|1].sum+=(tr[u<<1|1].r-tr[u<<1|1].l+1)*x;
tr[u<<1].lazy+=x,tr[u<<1|1].lazy+=x;
tr[u].lazy=0;
}
void modify(int u,int l,int r,int x){
if(tr[u].l>=l&&tr[u].r<=r){
tr[u].sum+=(tr[u].r-tr[u].l+1)*x;
tr[u].lazy+=x;
return ;
}
if(tr[u].lazy)
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid)
modify(u<<1,l,r,x);
if(r>mid)
modify(u<<1|1,l,r,x);
pushup(u);
}
ll query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
return tr[u].sum;
}
if(tr[u].lazy)
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
ll ans=0;
if(l<=mid)
ans+=query(u<<1,l,r);
if(r>mid)
ans+=query(u<<1|1,l,r);
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>q1>>k;
int i;
for(i=1;i<=n;i++){
cin>>a[i];
}
int flag=0,sign=0;
build(1,1,n);
for(i=1;i<=n;i++){
q[a[i]].push(i);
if(q[a[i]].size()==k+1){
flag=max(flag,q[a[i]].front());
q[a[i]].pop();
}
if(q[a[i]].size()==k){
sign=max(sign,q[a[i]].front());
}
if(sign>0){
f[i]=flag+1;
e[i]=sign;
}
}
for(i=1;i<=q1;i++){
int l,r;
cin>>l>>r;
num[r].push_back({l,i});
}
for(i=1;i<=n;i++){
if(e[i])
modify(1,f[i],e[i],1);
for(auto t:num[i]){
ans[t.id]=query(1,t.l,i);
}
}
for(i=1;i<=q1;i++){
cout<<ans[i]<<endl;
}
}