可求解多維偏序問題
三維偏序(陌上花開)
有 nn 個元素,第 ii 個元素有 、 、 三個屬性,設 表示滿足且 且 的 j 的數量。
對於 ,求 f(i) = d 的數量
輸入格式
第一行兩個整數 nn、kk,分別表示元素數量和最大屬性值。
之後 nn 行,每行三個整數 、 、 ,分別表示三個屬性值。
輸出格式
輸出 n 行,第 d + 1 行表示 f(i) = d的 i 的數量。
輸入輸出樣例
10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1
輸出
3
1
3
0
1
0
1
0
0
1
不同於普通分治的是:左右兩個子區間並不是獨立的,雖然不能使得兩個子區間相互獨立,但是通過某一維的排序,使得左子區間答案相對於右子區間獨立,而右子區間最終計算時加上左子區間的貢獻即可
因爲可以等於,如果不去重的話子區間答案可能不獨立。
如:a,b,c,d分爲ab,cd,如果b和c相等,分治就不對了
#include<bits/stdc++.h>
using namespace std;
char buf[1<<20],*P1=buf,*P2=buf;
#define gc() (P1==P2&&(P2=(P1=buf)+fread(buf,1,1<<20,stdin),P1==P2)?EOF:*P1++)
#define TT template<class T>inline
TT bool read(T &x){
x=0;char c=gc();bool f=0;
while(c<48||c>57){if(c==EOF)return 0;f^=(c=='-'),c=gc();}
while(47<c&&c<58)x=x*10+c-48,c=gc();
if(f)x=-x;return 1;
}
TT bool read(T&a,T&b){return read(a)&&read(b);}
TT bool read(T&a,T&b,T&c){return read(a)&&read(b)&&read(c);}
typedef long long ll;
#define lowbit(x) (x&(-x))
const ll MAXN=1e5+8,mod=1e9+7,inf=0x3f3f3f3f;
struct Node{int a,b,c,num,ans;}node[MAXN],tmp[MAXN];
//num:去重後的和數量,該點的答案
bool cmp(const Node&x,const Node&y){
if(x.a^y.a)return x.a<y.a;
if(x.b^y.b)return x.b<y.b;
return x.c<y.c;
}
bool equal(const Node&x,const Node&y){return x.a==y.a&&x.b==y.b&&x.c==y.c;}
int n,k,s[MAXN<<1];
inline void add(int p,int v){
while(p<=k){
s[p]+=v;
p+=lowbit(p);
}
}
inline int query(int p){
int res=0;
while(p){
res+=s[p];
p-=lowbit(p);
}return res;
}
int d[MAXN];
void cdq(int l,int r){
if(l==r)return;//如果只有一個點,ans=0;
int m=(l+r)>>1;
cdq(l,m);cdq(m+1,r);//遞歸求解子區間
for(int i=l,j=m+1,p=l;i<=m||j<=r;++p){//更新答案的同時就可以歸併排序
if(i<=m&&(j>r||node[i].b<=node[j].b))
add(node[i].c,node[i].num),tmp[p]=node[i++];
else node[j].ans+=query(node[j].c),tmp[p]=node[j++];
}
for(int i=l;i<=m;++i)add(node[i].c,-node[i].num);//將樹狀數組清空
for(int i=l;i<=r;++i)node[i]=tmp[i];
}
int main() {
read(n,k);
for(int i=1;i<=n;++i){
read(node[i].a,node[i].b,node[i].c);
node[i].num=1;
node[i].ans=0;
}
sort(node,node+1+n,cmp);
int cnt=1;//去重
for(int i=2;i<=n;++i){
if(equal(node[i],node[cnt]))node[cnt].num++;
else node[++cnt]=node[i];
}
cdq(1,cnt);
//這裏的ans是隻計算了不想等的答案,得加上重複的數量。
for(int i=1;i<=cnt;++i)d[node[i].ans+node[i].num-1]+=node[i].num;
for(int i=0;i<n;++i)printf("%d\n",d[i]);
return 0;
}