1. 程式人生 > >[bzoj4994][Usaco2017 Feb]Why Did the Cow Cross the Road III_樹狀陣列

[bzoj4994][Usaco2017 Feb]Why Did the Cow Cross the Road III_樹狀陣列

Why Did the Cow Cross the Road III bzoj-4994 Usaco-2017 Feb

題目大意:給定一個長度為$2n$的序列,$1~n$個出現過兩次,$i$第一次出現的位置記為$a_i$,第二次記為$b_i$,求滿足$a_i<a_j<b_i<b_j$的個數。

註釋:$1\le n\le 10^5$。


想法

這個題有一個非常不一樣的地方。

我記得我之前做過的長成這樣的題大概都是第一個位置+1,第二個位置-1即可。

這個題我們只能對第一個位置進行操作。

如果第一次碰見了這個數,就將當前位置+1

如果是第二次碰見了這個數,我們先更新答案,然後把這個數第一個出現的位置-1即可。

Code

#include <bits/stdc++.h>
#define N 100010 
using namespace std; typedef long long ll;
int tr[N<<2],vis[N],a[N<<1],n;
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
inline int lowbit(int x) {return x&(-x);}
void update(int x,int val) {for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=val;}
ll query(int x) {ll ans=0; for(int i=x;i;i-=lowbit(i)) ans+=tr[i]; return ans;}
int main()
{
	ll ans=0; n=rd()*2; for(int i=1;i<=n;i++) a[i]=rd(); for(int i=1;i<=n;i++)
	if(!vis[a[i]]) update(i,1),vis[a[i]]=i;
	else ans+=query(i)-query(vis[a[i]]),update(vis[a[i]],-1);
	cout << ans << endl ;
	return 0;
}

小結:樹狀陣列是非常有用的啊,要熟練掌握才是。