奇袭
问题 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]<ma[i]) t[ma[z]-z]-=1,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<iostream> #include<cstdio> #include<cstring> #include<cmath> #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<b ? a : b; } LL get(int l,int r) { if(l==r-1){ if(abs(a[l]-a[r])==1) return 3; else return 2; } if(l==r){ return 1; } LL ans=0; int mid=(l+r)/2; ans+=get(l,mid)+get(mid+1,r); ma[mid]=a[mid]; mi[mid]=a[mid]; for(int i=mid-1;i>=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]<ma[i]&&z<=r){ t[ma[z]-z+maxn]-=1; z++; } while(mi[z1]>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]<ma[i]&&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; }