看了晨神的题解,确实很厉害呀
http://blog.csdn.net/heheda_is_an_oier/article/details/51199299
这道题利用了数据随机的性质,单调队列中期望O(log n)个元素,这就非常有趣了。
我们把每个询问拆成两个,这样可以做差,右端点每往后移一个位置,对应加入一遍所有的答案,因为单调队列中有logn个元素,所以一共有logn中不同的答案。
线段树维护一下区间和和区间加操作就好了
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100010
#define mod 1000000000
using namespace std;
struct yts
{
int l,r;
long long tag,sum;
}t[4*maxn];
struct yts1
{
int l1,r1,r,op,id;
}q[maxn];
int a[maxn],st[maxn];
int n,m,top;
long long ans[maxn];
bool cmp(yts1 x,yts1 y)
{
return x.r<y.r;
}
void add(int i,long long x)
{
t[i].tag+=x;t[i].sum+=1ll*(t[i].r-t[i].l+1)*x;
}
void release(int i)
{
if (t[i].tag==0) return;
add(i<<1,t[i].tag);add(i<<1|1,t[i].tag);
t[i].tag=0;
}
void build(int i,int l,int r)
{
t[i].l=l;t[i].r=r;t[i].tag=t[i].sum=0;
if (l==r) return;
int mid=(l+r)/2;
build(i<<1,l,mid);build(i<<1|1,mid+1,r);
}
void modify(int i,int l,int r,int x)
{
if (l<=t[i].l && t[i].r<=r) {add(i,x);return;}
release(i);
int mid=(t[i].l+t[i].r)/2;
if (l<=mid) modify(i<<1,l,r,x);
if (mid<r) modify(i<<1|1,l,r,x);
t[i].sum=t[i<<1].sum+t[i<<1|1].sum;
}
long long query(int i,int l,int r)
{
if (l<=t[i].l && t[i].r<=r) return t[i].sum;
release(i);
int mid=(t[i].l+t[i].r)/2;long long ans=0;
if (l<=mid) ans+=query(i<<1,l,r);
if (mid<r) ans+=query(i<<1|1,l,r);
return ans;
}
int main()
{
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
n=max(n,max(r1,r2));
q[2*i-1]=(yts1){l1,r1,l2-1,-1,i};
q[2*i]=(yts1){l1,r1,r2,1,i};
}
long long bat1=1023,bat2=1025;
for (int i=1;i<=n;i++,bat1=bat1*1023ll%mod,bat2=bat2*1025ll%mod) a[i]=bat1^bat2;
sort(q+1,q+2*m+1,cmp);
build(1,1,n);
int top,k;
top=0;k=1;a[0]=0x7fffffff;
for (int i=0;i<=n;i++)
{
while (top && a[i]>a[st[top]]) top--;
st[++top]=i;
for (int j=2;j<=top;j++) modify(1,st[j-1]+1,st[j],a[st[j]]);
while (k<=2*m && q[k].r==i) ans[q[k].id]+=1ll*q[k].op*query(1,q[k].l1,q[k].r1),k++;
}
build(1,1,n);
top=0;k=1;a[0]=0;
for (int i=0;i<=n;i++)
{
while (top && a[i]<a[st[top]]) top--;
st[++top]=i;
for (int j=2;j<=top;j++) modify(1,st[j-1]+1,st[j],a[st[j]]);
while (k<=2*m && q[k].r==i) ans[q[k].id]-=1ll*q[k].op*query(1,q[k].l1,q[k].r1),k++;
}
for (int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}