problem:
一个圆上依次有1~2*n的数字。每个数字都有且只有另一个数字与他相连。选出三条线,使得每条线的两端之间隔的最少点(只包括被选择的6个点)的个数相等。
输入输出格式
输入格式:
The first line contains integer n(3<=n<=10^5) — the number of lines.
Each of the following n n n lines contains two integers ai,bi (1<=ai,bi<=2n), which means that there is a line carved on the ice connecting the ai –th and bi –th endpoint.
It's guaranteed that each endpoints touches exactly one line.
输出格式:
Print the number of ways to build the caves.
Please, do not write the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.
输入输出样例
输入样例#1:
4
5 4
1 2
6 7
8 3
输出样例#1:
2
输入样例#2:
8
1 7
2 4
3 9
5 11
6 8
10 16
13 15
14 12
输出样例#2:
6
说明
The second sample corresponds to the figure in the problem statement.
六个点三条边有以下五种可能:
明显只有第1个和第4个可以。但是这2个情况不好求
可以求出总方案再减去不合法方案
此题有两种写fa♂:
第一种是树状数组
假设当前直线i a->b(a<b)
在直线左边的直线数为x,右边的直线数为y,与i相♂蕉的直线数为z
显然有x+y+z+1=n
第3种情况就是x*y
第2,5种是(x+y)*z
但是因为每个点都有边连出,且圆上无蕉♂点
所以z=b-a-1-2*x
第二种是主席树,了解一下
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 typedef long long lol; 8 lol c[200001],n,m; 9 int a[200001],b[200001],p[200001]; 10 lol ans1,ans2,ans; 11 void add(int x,int d) 12 { 13 while (x<=m) 14 { 15 c[x]+=d; 16 x+=(x&(-x)); 17 } 18 } 19 int query(int x) 20 { 21 int s=0; 22 while (x) 23 { 24 s+=c[x]; 25 x-=(x&(-x)); 26 } 27 return s; 28 } 29 int main() 30 {int i; 31 cin>>n; 32 m=2*n; 33 for (i=1;i<=n;i++) 34 { 35 scanf("%d%d",&a[i],&b[i]); 36 p[a[i]]=b[i]; 37 p[b[i]]=a[i]; 38 } 39 for (i=1;i<=m;i++) 40 { 41 if (i<p[i]) continue; 42 int x=query(i)-query(p[i]-1); 43 int z=i-p[i]-1-x*2; 44 add(p[i],1); 45 int y=n-1-x-z; 46 ans1+=x*y; 47 ans2+=(x+y)*z; 48 } 49 ans=n*(n-1)*(n-2)/6; 50 cout<<ans-ans1-ans2/2; 51 }