Educational Codeforces Round 56 (Rated for Div. 2) E(1093E) Intersection of Permutations (树套树,pb_ds)
题意和分析在之前的链接中有:https://www.cnblogs.com/pkgunboat/p/10160741.html
之前补题用三维偏序的cdq的分治A了这道题,但是感觉就算比赛再次遇到类似的题可能写不出cdq的代码。。。这次算是自己独立A的了。。。
如果这题不卡常的话,什么树套什么树都可以,为了节省空间以及提高效率,我在外层写一个树状数组,树状数组的每一个节点用pb_ds的红黑树维护(红黑大法好),这样查询效率比较高。
为了方便红黑树的区间操作,每颗树插入1个负无穷,1个正无穷。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define INF 0x3f3f3f3f #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> #define lowbit(x) (x&(-x)) using namespace std; using namespace __gnu_pbds; const int maxn=200010; int a[maxn],b[maxn],pos[maxn],mp[maxn]; __gnu_pbds::tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> t[maxn]; __gnu_pbds::tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>::iterator itl,itr; int n,m,ql,qr; int query(int x){ int ans; itl=t[x].lower_bound(ql); itr=t[x].upper_bound(qr); return t[x].order_of_key(*itr)-t[x].order_of_key(*itl); } int ask(int x){ int ans=0; for(;x;x-=lowbit(x)) ans+=query(x); return ans; } void build(int n){ for(int i=1;i<=n;i++){ for(int j=i-lowbit(i)+1;j<=i;j++) t[i].insert(mp[j]); t[i].insert(-INF); t[i].insert(INF); } } void maintain(int x,int y){ if(y<0){ if(t[x].find(-y)!=t[x].end()) t[x].erase(-y); } else{ t[x].insert(y); } } void add(int x,int y){ for(;x<=n;x+=lowbit(x)) maintain(x,y); } int main(){ int l,r,x,op; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&x); pos[x]=i; } for(int i=1;i<=n;i++){ scanf("%d",&x); mp[i]=pos[x]; } build(n); while(m--){ scanf("%d",&op); if(op==1){ scanf("%d%d%d%d",&ql,&qr,&l,&r); printf("%d\n",ask(r)-ask(l-1)); } else{ scanf("%d%d",&l,&r); add(l,-mp[l]); add(r,-mp[r]); swap(mp[l],mp[r]); add(l,mp[l]); add(r,mp[r]); } } }
代码比较:
cdq分治:
树套树:
明显cdq分治更快,而树套树的内存占用更少(不太科学)。
以本辣鸡的码力,如果要用线段树这些常数比较大的树应该要超时。。。