给定一个有n个元素的序列,元素编号为1~n,每个元素有三个属性a,b,c,求序列中满足 i<j i < j 且 ai<aj a i < a j 且 bi<bj b i < b j 且 ci<cj c i < c j 的数对 (i,j) ( i , j ) 的个数。
第一行一个整数 n n ,表示序列长度。
第二行 n n 个整数,分别表示 a1∼an a 1 ∼ a n 。
第三行 n n 个整数,分别表示 b1∼bn b 1 ∼ b n 。
第四行 n n 个整数,分别表示 c1∼cn c 1 ∼ c n 。
一个整数,表示答案。
5
1 5 3 4 2
2 5 3 4 1
1 2 5 3 4
3
满足条件的 (i,j) ( i , j ) 共有以下三对:
(1,2) ( 1 , 2 )
(1,3) ( 1 , 3 )
(1,4) ( 1 , 4 )
对于30%的数据, n≤5000 n ≤ 5000 。
对于100%的数据, 1≤n≤50000 1 ≤ n ≤ 50000 ,保证所有的 ai、bi、ci a i 、 b i 、 c i 分别组成三个 1∼n 1 ∼ n 的排列。
HZOI 2016
四维偏序模板题…
我们当然可以 CDQ C D Q 套树套树, 但是在这里介绍一种 CDQ C D Q 套 CDQ C D Q 的写法。
第一维:我们通过排序解决。(在这里就是输入顺序)
第二维:我们 CDQ C D Q 在 buf b u f 数组里实现对其的排序, 递归处理。 同时处理 [lef,rig] [ l e f , r i g ] 区间时, 将 [lef,mid] [ l e f , m i d ] 区间打上标记表示其第一维较小。
第三维:我们 CDQ C D Q 在 buf2 b u f 2 数组里实现对其的排序。 当然 buf2 b u f 2 是基于 buf b u f 得到的。
第四维: BIT B I T 维护前缀和即可。 注意修改、查询的条件是第一维第二维都较小。 这时我们就可以利用打的标记来判定了。
如果还是不懂的同学可以看代码…
#include
#include
#include
#include
#include
#include
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 50050
#define File freopen("partial_order.in", "r", stdin), freopen("partial_order.out", "w", stdout)
#define lbt(i) (i & -i)
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
W (!isdigit(c)) c = gc;
W (isdigit(c))
x = (x << 1) + (x << 3) + c - 48, c = gc;
}
struct Node
{
int a, b, c, d;
bool typ;
}eve[MX], buf[MX], buf2[MX];
int dot, tree[MX];
long long ans;
namespace BIT
{
IN void clear(R int now)
{
W (now <= dot)
if(tree[now]) tree[now] = 0, now += lbt(now);
else return;
}
IN void add(R int now)
{W (now <= dot) ++tree[now], now += lbt(now);}
IN int query(R int now)
{
int ret = 0;
W (now) ret += tree[now], now -= lbt(now);
return ret;
}
}
void cdq2(const int &lef, const int &rig)
{
if(lef == rig) return;
int mid = lef + rig >> 1;
cdq2(lef, mid), cdq2(mid + 1, rig);//先递归保证左右区间c单增, 并且左区间b值小于右区间b值
int lb = lef, rb = mid + 1, cur = lef;
W (lb <= mid && rb <= rig)
{
if(buf[lb].c < buf[rb].c)
{
if(!buf[lb].typ) BIT::add(buf[lb].d);//必须a值更小才能更新
buf2[cur++] = buf[lb++];
}
else
{
if(buf[rb].typ) ans += BIT::query(buf[rb].d);//必须a值更大才能计入结果
buf2[cur++] = buf[rb++];
}
}
W (lb <= mid) buf2[cur++] = buf[lb++];
W (rb <= rig)
{
if(buf[rb].typ) ans += BIT::query(buf[rb].d);
buf2[cur++] = buf[rb++];
}
for (R int i = lef; i <= mid; ++i) if(!buf[i].typ) BIT::clear(buf[i].d);
for (R int i = lef; i <= rig; ++i) buf[i] = buf2[i];
}
void cdq1(const int &lef, const int &rig)//处理b
{
if(lef == rig) return;
int mid = lef + rig >> 1;
cdq1(lef, mid), cdq1(mid + 1, rig);//先递归保证左右区间b单增
int lb = lef, rb = mid + 1, cur = lef;
W (lb <= mid && rb <= rig)
{
if(eve[lb].b < eve[rb].b) buf[cur++] = eve[lb++], buf[cur - 1].typ = false;
else buf[cur++] = eve[rb++], buf[cur - 1].typ = true;
}
W (lb <= mid) buf[cur++] = eve[lb++], buf[cur - 1].typ = false;
W (rb <= rig) buf[cur++] = eve[rb++], buf[cur - 1].typ = true;
for (R int i = lef; i <= rig; ++i) eve[i] = buf[i];
cdq2(lef, rig);
}
int main(void)
{
File;
in(dot);
for (R int i = 1; i <= dot; ++i) in(eve[i].b), eve[i].a = i;
for (R int i = 1; i <= dot; ++i) in(eve[i].c);
for (R int i = 1; i <= dot; ++i) in(eve[i].d);
cdq1(1, dot);
printf("%lld", ans);
}