1. 程式人生 > >[bzoj] 1176 Mokia || CDQ分治

[bzoj] 1176 Mokia || CDQ分治

沒有 query www. pan etc lin cpp read 需要

原題

給出W×W的矩陣(S沒有用,題目有誤),給出無限次操作,每次操作的含義為:
輸入1:你需要把(x,y)(第x行第y列)的格子權值增加a
輸入2:你需要求出以左下角為(x1,y1),右上角為(x2,y2)的矩陣內所有格子的權值和,並輸出
輸入3:表示輸入結束


因為修改之間相互獨立,所以可以用CDQ。
三個維度分別為時間,x軸,y軸。
簡單的三維偏序即可。

#include<cstdio>
#include<algorithm>
#define N 100010
#define M 200010
using namespace std;
struct hhh
{
    int x,y,z,cnt,sum;
    inline
bool operator == (const hhh &b) const { return x==b.x && y==b.y && z==b.z; } inline bool operator < (const hhh &b) const { if (x!=b.x) return x<b.x; if (y!=b.y) return y<b.y; return z<b.z; } inline bool operator
> (const hhh &b) const { if (y!=b.y) return y<b.y; return z<=b.z; } }t[N],a[N]; int m,head,tail,ans[N],n,s,f[M]; int read() { int ans=0,fu=1; char j=getchar(); for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1; for (;j>='0'
&& j<='9';j=getchar()) ans*=10,ans+=j-'0'; return ans*fu; } void init(int x) { while (x<=s) { if (f[x]) f[x]=0; else break; x+=x&-x; } } int query(int x) { int ans=0; while (x) { ans+=f[x]; x-=x&-x; } return ans; } void insert(int x,int y) { while (x<=s) { f[x]+=y; x+=x&-x; } } void CDQ(int l,int r) { if (l==r) return ; int mid=(l+r)>>1,idx1=l,idx2=mid+1; CDQ(l,mid); CDQ(mid+1,r); for (int i=l;i<=r;i++) { if (idx2>r || idx1<=mid && a[idx1]>a[idx2]) { t[i]=a[idx1++]; insert(t[i].z,t[i].cnt); } else { t[i]=a[idx2++]; t[i].sum+=query(t[i].z); } } for (int i=l;i<=r;i++) { a[i]=t[i]; init(a[i].z); } } int main() { m=read(); s=read(); for (int i=1;i<=m;i++) { t[i].x=read(); t[i].y=read(); t[i].z=read(); } sort(t+1,t+m+1); head=1; n=0; while (head<=m) { tail=head+1; while (tail<=m && t[tail]==t[head]) ++tail; a[++n]=t[head]; a[n].cnt=tail-head; head=tail; } CDQ(1,n); for (int i=1;i<=n;i++) ans[a[i].sum+a[i].cnt-1]+=a[i].cnt; for (int i=0;i<m;i++) printf("%d\n",ans[i]); return 0; }

[bzoj] 1176 Mokia || CDQ分治