题目大意
给定
n
个限制,每个形如
你要生成
n
的排列
请判断生成的排列中逆序对个数为奇数的排列多还是偶数的排列多。
一个测试点
T
组数据。
题目分析
题目中既有排列又有逆序对个数奇偶性,这启发我们从矩阵行列式入手。
考虑构造一个
n
阶矩阵,对于第
但是这题
n
很大,我们不能直接高斯消元。考虑利用矩阵的特殊性质来快速消元。
注意到题目中的矩阵每一行有值的都是一段区间(且值都是
将限制挂在
Li
上,并且记录它的
Ri
以及原本是哪一行(
i
)。
然后我们从左到右消。假设我们考虑到位置
也就是说我们需要支持若干个集合的取最小值以及合并,使用左偏树就好了。
时间复杂度
O(nlogn)
。
代码实现
#include <algorithm>
#include <iostream>
#include <cassert>
#include <cstdio>
#include <cctype>
#include <queue>
using namespace std;
const int N=100050;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
int idx[N],rel[N],root[N];
int T,n;
namespace leftist_tree
{
int rank[N],key[N],cid[N];
int son[N][2];
queue<int> avl;
void init()
{
for (;!avl.empty();avl.pop());
for (int i=1;i<=n;++i) root[i]=0,avl.push(i);
}
int newnode(int val,int id)
{
int ret=avl.front();avl.pop();
return key[ret]=val,cid[ret]=id,son[ret][0]=son[ret][1]=0,rank[ret]=1,ret;
}
void release(int x){avl.push(x);}
int merge(int x,int y)
{
if (!x||!y) return x^y;
if (key[x]>key[y]) swap(x,y);
son[x][1]=merge(son[x][1],y);
if (rank[son[x][0]]<rank[son[x][1]]) swap(son[x][0],son[x][1]);
rank[x]=rank[son[x][1]]+1;
return x;
}
void push(int &rt,int val,int id){rt=merge(newnode(val,id),rt);}
void pop(int &rt,int &key_,int &id_){key_=key[rt],id_=cid[rt],release(rt),rt=merge(son[rt][0],son[rt][1]);}
};
int main()
{
freopen("fiend.in","r",stdin),freopen("fiend.out","w",stdout);
for (T=read();T--;putchar('\n'))
{
n=read(),leftist_tree::init();
for (int i=1,l,r;i<=n;++i) idx[i]=rel[i]=i,l=read(),r=read(),leftist_tree::push(root[l],r,i);
int ret=1;
for (int i=1;ret&&i<=n;++i)
{
int key_,id_;
for (;root[i]&&leftist_tree::key[root[i]]<i;leftist_tree::pop(root[i],key_,id_));
if (!root[i]) ret=0;
else
{
leftist_tree::pop(root[i],key_,id_);
int tmp=idx[id_];
if (tmp!=i) ret*=-1,swap(idx[id_],idx[rel[i]]),swap(rel[i],rel[tmp]);
if (key_<n) root[key_+1]=leftist_tree::merge(root[i],root[key_+1]);
}
}
/*for (int i=1;i<=n;++i) cerr<<idx[i]<<' ';
cerr<<endl;
for (int i=1;i<=n;++i) cerr<<rel[i]<<' ';
cerr<<endl;
for (int i=1;i<=n;++i) assert(rel[idx[i]]==i);*/
if (ret>0) putchar('Y');
else if (!ret) putchar('D');
else putchar('F');
}
fclose(stdin),fclose(stdout);
return 0;
}