您的位置:首页 > 其它

codeforces 387C George and Number

2014-02-25 13:44 302 查看
这道题目的意思是对于每个要删除的数字,向前或向后找到一块连续的数字,而它是其中最小的;

很容易看出对于所有要先删除的数字要从大到小删除;

然后对于每个要删除的字母,要找到比他小的,但是在原数列中又靠它最近的数字;

这样的话,很直观最多只能用lg n的复杂度来处理这个问题;

可以用二分查找,也可以用set来代替;

考虑到前面删除的一些数字不能计算进去,还要一个快速计算区间和的算法,用树状数组和线段树都可以;

不过看到tags,上面写着还可以用dsu(disjoint set union)并查集来做;

感觉挺神奇的,想到了之后再补上!

#include<cstdio>
#include<iostream>
#define maxn 1000006
using namespace std;
int n,m;
int pos[maxn];
bool can[maxn];
int size[maxn];
int f[maxn];
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}

void dsu_union(int x,int y)
{
int a=find(x);
int b=find(y);
if(a==b)return;
f[b]=a;
size[a]+=size[b];
size[b]=0;
}

void interval_union(int p)
{
if(p>0&&!can[p-1])
dsu_union(p,p-1);
if(p<n&&!can[p+1])
dsu_union(p,p+1);
}

int main()
{
int num,p;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&num);
pos[num]=i;
f[i]=i;
}
for(int i=1;i<=m;i++)
{
scanf("%d",&num);
can[pos[num]]=1;
}
for(int i=1;i<=n;i++)
if(!can[i])
interval_union(i);
long long ans=0;
for(int i=n;i>=1;i--)
{
p=pos[i];
num=find(p);
size[num]++;
if(!can[p])
ans+=size[num];
else
{
can[p]=0;
interval_union(p);
}
}
cout<<ans;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: