问题 C: 奇袭
时间限制: 1 Sec 内存限制: 256 MB提交: 133 解决: 26
[ 提交][ 状态]
题目描述
由于各种原因,桐人现在被困在Under World(以下简称UW)中,而UW马上 要迎来最终的压力测试——魔界入侵。
唯一一个神一般存在的Administrator被消灭了,靠原本的整合骑士的力量 是远远不够的。所以爱丽丝动员了UW全体人民,与整合骑士一起抗击魔族。
在UW的驻地可以隐约看见魔族军队的大本营。整合骑士们打算在魔族入侵前 发动一次奇袭,袭击魔族大本营!
为了降低风险,爱丽丝找到了你,一名优秀斥候,希望你能在奇袭前对魔族 大本营进行侦查,并计算出袭击的难度。
经过侦查,你绘制出了魔族大本营的地图,然后发现,魔族大本营是一个N ×N的网格图,一共有N支军队驻扎在一些网格中(不会有两只军队驻扎在一起)。
在大本营中,每有一个k×k(1≤k≤N)的子网格图包含恰好k支军队,我们袭 击的难度就会增加1点。
现在请你根据绘制出的地图,告诉爱丽丝这次的袭击行动难度有多大。
输入
第一行,一个正整数N,表示网格图的大小以及军队数量。
接下来N行,每行两个整数,Xi,Yi,表示第i支军队的坐标。
保证每一行和每一列都恰有一只军队,即每一个Xi和每一个Yi都是不一样 的。
输出
样例输入
5
1 1
3 2
2 4
5 5
4 3
样例输出
10
问题可以转化为一个长度为n的序列,求有多少个连续的子区间
定义ma[i]表示[i,mid]([mid+1,i])的最大值,mi[i]表示[i,mid]([mid+1,i])的最小值
分值考虑每一个区间的ans
对于[l,r]的一段区间,ans=两个子区间的ans之和加上跨mid的情况
1.最大值和最小值在同一侧,枚举每个点做边界,通过ma[i],mi[i]计算出另一个边界,如果符合情况就+1
2.最大值和最小值在异侧,加入最小值在左边i,最大值在右边j,j-i=ma[j]-mi[i]
得ma[j]-j=mi[i]-i;
两个指针z,z1从mid+1向r移动,while(ma[z]
while(mi[z1]>mi[i]) t[ma[z1]-z1]+=1,z1++;
根据ma[],mi[]单调可知,z右边的点肯定满足ma[j]>ma[i],z1左边的点满足mi[j]>mi[i],z到z1中间的点都可能是合法边界,ans+=t[mi[i]-i]
mi[i]-i可能为负数,再加上一个maxn,另一种情况类似
#include
#include
#include
#include
#define maxn 50000
#define INF 100000
#define LL long long
using namespace std;
int n;
int a[maxn+5];
int ma[maxn+5],mi[maxn+5];
int t[maxn*2+5];
int max(int a,int b)
{
return a>b ? a : b;
}
int min(int a,int b)
{
return a=l;i--){
ma[i]=max(ma[i+1],a[i]);
mi[i]=min(mi[i+1],a[i]);
}
ma[mid+1]=a[mid+1],mi[mid+1]=a[mid+1];
for(int i=mid+2;i<=r;i++){
ma[i]=max(ma[i-1],a[i]);
mi[i]=min(mi[i-1],a[i]);
}
int op;
for(int i=mid;i>=l;i--){
op=ma[i]-mi[i]+i;
if(op<=r&&op>mid&&ma[op]<=ma[i]&&mi[op]>=mi[i]) ans++;
}
for(int i=mid+1;i<=r;i++){
op=i-(ma[i]-mi[i]);
if(op>=l&&op<=mid&&ma[op]<=ma[i]&&mi[op]>=mi[i]) ans++;
}
for(int i=l;i<=r;i++){
t[ma[i]-i+maxn]=0; t[mi[i]-i+maxn]=0;
}
int z=mid+1,z1=mid+1;
for(int i=mid;i>=l;i--){
while(ma[z]mi[i]&&z1<=r){
t[ma[z1]-z1+maxn]+=1;
z1++;
}
ans+=max(t[mi[i]-i+maxn],0);
if(z==r+1) break;
}
for(int i=l;i<=r;i++){
t[ma[i]+i]=0; t[mi[i]+i]=0;
}
z=mid,z1=mid;
for(int i=mid+1;i<=r;i++){
while(ma[z]=l){
t[ma[z]+z]-=1;
z--;
}
while(mi[z1]>mi[i]&&z1>=l){
t[ma[z1]+z1]+=1;
z1--;
}
ans+=max(t[mi[i]+i],0);
if(z==l-1) break;
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("raid1.in","r",stdin);
int x,y;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&x,&y);
a[x]=y;
}
printf("%lld\n",get(1,n));
//while(1);
return 0;
}