B. Hossam and Friends
这个题的大意是输入一些样例,样例中的每一对数是关系不好的人的序号,现在在一个序列中要统计出所有好区段的数目。(好区段是这样定义的:在
[
a
,
a
+
1
,
.
.
,
b
]
[a,a+1,..,b]
[a,a+1,..,b]这个闭区间里面不能有关系不好的人。)
嗯,俺用的方法是线段树,但是应该没有这么麻烦,好像逆序一下就行。我是这样的想的:考虑每一个元素向右可以产生的好区段。比如说:有这样的排序:
a
,
b
,
c
,
d
,
e
,
f
a,b,c,d,e,f
a,b,c,d,e,f;
d
d
d和
f
f
f的关系不好,
c
c
c和
e
e
e的关系不好,那么
a
a
a和
b
b
b向右延,最远能到哪呢?很明显,可以到
d
d
d,也就是现在我得知了一系列的关系不好的朋友对:
p
i
,
q
i
p_{i},q_{i}
pi,qi;那么
p
i
p_{i}
pi(含)往左的所有人向右延,都不能到
q
i
q_{i}
qi,也就是要在线段树
[
1
,
p
i
]
[1,p_{i}]
[1,pi]区间上更新成
q
i
q_{i}
qi,而这个线段树维护的是最小值,如果有
p
i
p_{i}
pi的另一个
q
i
1
q_{i1}
qi1比
q
i
q_{i}
qi还小,就起到了作用。
代码:
#include<iostream>
#include<cstdio>
#include<vector>
#define min(a,b)(a<b)?a:b
using namespace std;
typedef long long ll;
void update(int L, int R, int l, int r, int cnt, int v, vector<int> &tree)
{
if (l > R || r < L)
return;
if (l >= L && r <= R)
{
tree[cnt] = min(tree[cnt], v);
return;
}
int mid = (l + r) / 2;
update(L, R, l, mid, cnt * 2, v, tree);
update(L, R, mid + 1, r, cnt * 2 + 1, v, tree);
//tree[cnt] = min(tree[cnt * 2], tree[cnt * 2 + 1]);
}
int query(int L, int R, int l, int r, int cnt, vector<int> &tree)
{
if (l > R || r < L)
return INT_MAX;
if (l >= L && r <= R)
{
return tree[cnt];
}
int mid = (l + r) / 2;
tree[cnt * 2] = min(tree[cnt * 2], tree[cnt]);
tree[cnt * 2 + 1] = min(tree[cnt * 2 + 1], tree[cnt]);
int a = query(L, R, l, mid, cnt * 2, tree);
int b = query(L, R, mid + 1, r, cnt * 2 + 1, tree);
return min(a, b);
}
int main(void)
{
int t;
scanf_s("%d", &t);
for (int i = 0; i < t; i++)
{
int n, m;
scanf_s("%d%d", &n, &m);
if (m == 0)
{
printf("%lld\n", (ll)n*(n + 1) / 2);
continue;
}
vector<int> tree(n << 3, n);
for (int i = 0; i < m; i++)
{
int a, b;
scanf_s("%d%d", &a, &b);
if (a > b)
{
int tmp = b;
b = a;
a = tmp;
}
update(1, a, 1, n,1, b - 1,tree);
}
ll sum = 0;
int j = 1;
while(j<=n)
{
int yh = query(j, j, 1, n, 1,tree);
ll q = yh - j + 1;
sum = sum +q;
j++;
}
printf("%lld\n", sum);
}
}
另一种方法(能看别人的代码真好)
这个就是把每一对对应的最小值用数组记录下来了,然后逆序走一遍
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll i,j,k,n,m,t,a[100500],res;
int main(){
cin>>t;
while(t--){
cin>>n>>m;
for(i=1;i<=n;i++)a[i]=n;
for(i=1;i<=m;i++){
cin>>j>>k;
if(k<j)swap(j,k);
a[j]=min(a[j],k-1);
}
res=n;
for(i=n-1;i>=1;i--){
a[i]=min(a[i],a[i+1]);
res+=a[i]-i;
}
cout<<res<<endl;
}
}