[bzoj] 1176 Mokia || CDQ分治
阿新 • • 發佈:2017-12-18
沒有 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分治