【数据结构】【杂题】jzoj 6342.Tiny Counting
较为简单的一个计数题目。
我们可以将这个题目拆开来想:
1.不考虑重复点,求全部情况:
假设情况1为
共p种。
情况2为
共q种,那么答案ans=qp。
2.考虑重复的情况:
重复的情况,无非就是两组共用了同一个端点。
设点(i,si),那么当a=d时,有(c<a<b&&sa<sb&&sa<sc)
在坐标系上就是这样表示的:
将绿色部分的点数*蓝色部分的点数就得到了这部分的结果。
其余类似,可以发现ans=pq-(a+b)(c+d),你可以认为abcd表示四个象限。
要离散化,用树状数组搞搞就能出来了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll N=2e5+10; 5 ll n_,n,ans; 6 ll b[N],aa[N],bb[N],cc[N],dd[N]; 7 struct poll{ 8 ll size,idx; 9 }a[N]; 10 ll arr[N]; 11 ll lb(ll x){return x&-x;} 12 void add(ll x){for(;x<=n;x+=lb(x))arr[x]++;} 13 ll pre(ll x){ll ans_=0;for(;x;x-=lb(x))ans_+=arr[x];return ans_;} 14 bool cmp(poll x,poll y){ 15 return x.size<y.size; 16 } 17 ll read(){ 18 ll x=0,f=1; 19 char c=getchar(); 20 while(!isdigit(c)){ 21 if(c=='-') f=-1; 22 c=getchar(); 23 } 24 while(isdigit(c)){ 25 x=x*10+c-'0'; 26 c=getchar(); 27 } 28 return x*f; 29 } 30 int main(){ 31 freopen("a.in","r",stdin); 32 freopen("a.out","w",stdout); 33 n_=read(); 34 for(ll i=1;i<=n_;i++){ 35 a[i].size=read(); 36 a[i].idx=i; 37 } 38 sort(a+1,a+n_+1,cmp); 39 a[0].size=-1; 40 for(ll i=1;i<=n_;i++){ 41 if(a[i].size>a[i-1].size) ++n; 42 b[a[i].idx]=n; 43 } 44 ll t1=0,t2=0; 45 for(ll i=1;i<=n_;i++){ 46 bb[i]=pre(b[i]-1); 47 dd[i]=pre(n)-pre(b[i]); 48 t1+=bb[i],t2+=dd[i]; 49 add(b[i]); 50 } 51 ans=t1*t2; 52 memset(arr,0,sizeof(arr)); 53 for(ll i=n_;i>=1;i--){ 54 cc[i]=pre(b[i]-1); 55 aa[i]=pre(n)-pre(b[i]); 56 ans-=(aa[i]+bb[i])*(cc[i]+dd[i]); 57 add(b[i]); 58 } 59 printf("%lld",ans); 60 return 0; 61 }
——抓住了时间,却不会利用的人,终究也逃不过失败的命运。