BZOJ2441: [中山市选2011]小W的问题
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2441
首先要注意到x1>x3且x5>x3(要是没有这个设定就是树状数组水题了。。
这题正反做两个V乘起来就是答案了。。
对y排序,每一个点找出在它左上方的点的个数记为sum,然后只要我们每次访问一个点的时候就把它对于在它右边的点的贡献全部删掉,那么询问一个点的答案就是在它左边所有点的sum之和了。
具体写起来比较烦。。
Orz http://blog.csdn.net/u012288458/article/details/48880559
按id开线段树,每个点维护两个域分别表示相同点中最左那个点的id和第一个比它大的点的id
首先这个算点的贡献,要这个点已经被计算过才可以减掉贡献,可以开一个变量来记录当前区间有多少个点已经被计算过。
然后减贡献的时候,可以让这个点右边的所有的点都减掉贡献。然后加上贡献的时候只要也加上左边所有点点数就可以了。
但是这样做的话要注意分开来做。毕竟贡献要全部减完才能来计算答案。。
#include<cstring> #include<iostream> #include<cstdio> #include<algorithm> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define ll long long #define low(i) (i&(-i)) #define maxn 200500 #define mm 1000000007 #define inf 2000000000 using namespace std; struct node{int l,r,len; ll tag,sum; }t[maxn*4]; struct data{int x,x2,y,id; }a[maxn]; ll c[maxn],f[maxn][2]; int n,tot,b[maxn]; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();} return x*f; } bool cmp(data a,data b){ return a.x<b.x; } bool cmp2(data a,data b){ return a.y<b.y; } void up(int i){ if (t[i].l==t[i].r) return; t[i].sum=0; t[i].len=t[i*2].len+t[i*2+1].len; if (t[i*2].len) t[i].sum=(t[i].sum+t[i*2].sum)%mm; if (t[i*2+1].len) t[i].sum=(t[i].sum+t[i*2+1].sum)%mm; } void push(int i,ll val){ t[i].tag=(t[i].tag+val)%mm; t[i].sum=(t[i].sum+1LL*val*t[i].len)%mm; } void Down(int i){ if (t[i].l==t[i].r) return; if (t[i].tag){ push(i*2,t[i].tag); push(i*2+1,t[i].tag); t[i].tag=0; } } ll query(int i,int L,int R){ if (L>R) return 0; if (t[i].len==0) return 0; int l=t[i].l,r=t[i].r,mid=(l+r)/2; Down(i); if (L<=l&&r<=R) return t[i].sum; if (R<=mid) return query(i*2,L,R); else if (L>mid) return query(i*2+1,L,R); else return (query(i*2,L,mid)+query(i*2+1,mid+1,R))%mm; } void change(int i,int pos,ll val){ Down(i); if (t[i].l==t[i].r) {t[i].len=1; t[i].sum=(t[i].tag+val)%mm; return;} int mid=(t[i].l+t[i].r)/2; if (pos<=mid) change(i*2,pos,val); else change(i*2+1,pos,val); up(i); } void change2(int i,int L,int R,ll val){ if (L>R) return; Down(i); int l=t[i].l,r=t[i].r,mid=(l+r)/2; if (L<=l&&r<=R){ push(i,val); return; } if (R<=mid) change2(i*2,L,R,val); else if (L>mid) change2(i*2+1,L,R,val); else change2(i*2,L,mid,val),change2(i*2+1,mid+1,R,val); up(i); } void build(int i,int l,int r){ t[i].l=l; t[i].r=r; t[i].sum=t[i].tag=t[i].len=0; if (l==r) return; int mid=(l+r)/2; build(i*2,l,mid); build(i*2+1,mid+1,r); } void solve(){ build(1,1,n); sort(a+1,a+1+n,cmp2); rep(i,1,n){ int j=i; while (j<n&&a[i].y==a[j+1].y) j++; rep(k,i,j) change2(1,a[k].x2,n,-1); rep(k,i,j) f[a[k].id][0]=query(1,1,a[k].x-1); rep(k,i,j) change(1,a[k].id,a[k].x-1); i=j; } } void solve2(){ build(1,1,n); sort(a+1,a+1+n,cmp2); rep(i,1,n){ int j=i; while (j<n&&a[i].y==a[j+1].y) j++; rep(k,i,j) change2(1,1,a[k].x-1,-1); rep(k,i,j) f[a[k].id][1]=query(1,a[k].x2,n); rep(k,i,j) change(1,a[k].id,n-a[k].x2+1); i=j; } } int main(){ n=read(); rep(i,1,n){ a[i].x=read(); a[i].y=read(); b[++tot]=a[i].x; } b[++tot]=inf; sort(b+1,b+1+tot); sort(a+1,a+1+n,cmp); rep(i,1,n) a[i].x2=upper_bound(b+1,b+1+tot,a[i].x)-b,a[i].x=lower_bound(b+1,b+1+tot,a[i].x)-b,a[i].id=i; solve(); solve2(); ll ans=0; rep(i,1,n) ans=(ans+f[i][0]*f[i][1]%mm)%mm; printf("%lld\n",ans); return 0; }