链接:https://ac.nowcoder.com/acm/contest/3005/H
来源:牛客网
大致题意:让我们针对每一个数,求这个数左区间和右区间颜色相同(也就是数字相同)得对数;
比如:左边3个“3'得颜色,右边2个‘3’得颜色,就有2*3=6对;
数据范围为5e5;所以可接受得复杂度为nlogn;
那么我们可以考虑线段树;
如何维护呢?
我们用两个vis去标记左边和右边各种颜色的个数;代码中visa标记的是右区间,visb标记的是左区间;
然后从左往右遍历一遍:
在某一次操作中,我们对第K个数求值;那么我们需要先把右区间颜色k的减1;
这个时候假如左区间有这个K数,我们就需要将这个数包含的对数求出来,然后update,
这里有个细节,假如k-1==k,那么需要减掉的对数要减1;
因为k-1并没有在上次的操作中计算;
然后,我们就求K-1这个位置的颜色在右区间的个数,然后将这个数update;
在跑一遍线段树求出第K个数的query(l,r,1)即可;
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=5e5+10; 5 int visa[maxn]; 6 int visb[maxn]; 7 ll ans[maxn]; 8 struct node 9 { 10 int val,l,r; 11 }a[maxn]; 12 struct haa 13 { 14 int l;int r; 15 ll sum; 16 }tree[maxn<<2]; 17 void build(int l,int r,int root) 18 { 19 tree[root].l=l;tree[root].r=r; 20 tree[root].sum=0; 21 if(l==r) return; 22 int mid=l+r>>1; 23 build(l,mid,root<<1); 24 build(mid+1,r,root<<1|1); 25 } 26 void up(int root) 27 { 28 tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum; 29 } 30 void update(int pos,int val,int root) 31 { 32 int L=tree[root].l; 33 int R=tree[root].r; 34 if(L==R){ 35 tree[root].sum+=val; 36 return; 37 } 38 int mid=L+R>>1; 39 if(pos<=mid) update(pos,val,root<<1); 40 else update(pos,val,root<<1|1); 41 up(root); 42 } 43 ll query(int l,int r,int root) 44 { 45 int L=tree[root].l; 46 int R=tree[root].r; 47 if(l<=L&&r>=R){ 48 return tree[root].sum; 49 } 50 ll ans=0; 51 int mid=L+R>>1; 52 if(l<=mid) ans+=query(l,r,root<<1); 53 if(r>mid) ans+=query(l,r,root<<1|1); 54 return ans; 55 } 56 int main() 57 { 58 int n; 59 scanf("%d",&n); 60 for(int i=1;i<=n;i++){ 61 scanf("%d%d%d",&a[i].val,&a[i].l,&a[i].r); 62 visa[a[i].val]++; 63 } 64 build(1,maxn,1); 65 ans[1]=0; 66 visa[a[1].val]--; //右区间-- 67 visb[a[1].val]++; //左区间++; 68 for(int i=2;i<=n;i++){ 69 visa[a[i].val]--; //右区间--; 70 if(visb[a[i].val]){ //如果左区间包含这个数的话; 71 //我们就需要减掉与这个数相关的对数; 72 //但是左区间包含i-1这一项;而这一项在上次操作中没有出现; 73 //所以当两者相等的时候,tmp--; 74 int tmp=visb[a[i].val]; 75 if(a[i-1].val==a[i].val) tmp--; 76 update(a[i].val,-tmp,1); 77 } 78 int tmp=visa[a[i-1].val]; 79 update(a[i-1].val,tmp,1); 80 ans[i]=query(a[i].l,a[i].r,1); 81 visb[a[i].val]++; 82 } 83 for(int i=1;i<=n;i++) 84 printf("%lld ",ans[i]); 85 printf("\n"); 86 return 0; 87 }