COGS 2479 偏序 题解

【题意】

给定一个有n个元素的序列,元素编号为1~n,每个元素有三个属性a,b,c,求序列中满足i<j且ai<aj且bi<bj且ci<cj的数对(i,j)的个数。

对于30%的数据,n<=5000。

对于100%的数据,1<=n<=50000(原题写错了哈哈),保证所有的ai、bi、ci分别组成三个1~n的排列。

【解法】

标题已经说了这是偏序,读完题,这就是个四维偏序模板题(位置一维,a,b,c剩下三维)。

解法多多,我用的是CDQ树套树(树套树写的树状数组套替罪羊树,毕竟在我的印象里替罪羊树在随机数据下跑得飞快)。

第一维已经有序,不用我们预处理,这样就可以按第一维(位置)分治,再把第二维(a)排序,剩下的第三维(b)和第四维(c)直接树套树就可以了(我用的是第三维树状数组,第四维平衡树)。

当然写CDQ套CDQ+树状数组应该也可以,然而本鶸渣不会写……

也可以写树套树套树……然而怎么写……

贴个代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define siz(x) ((x)?((x)->size):(0))
  5 #define lowbit(x) ((x)&(-(x)))
  6 using namespace std;
  7 const int maxn=50010;
  8 const double A=0.65;
  9 struct node{//Scapegoat Tree
 10     int data,size;
 11     node *lc,*rc,*prt;
 12     node(int d=0):data(d),size(1),lc(NULL),rc(NULL),prt(NULL){}
 13     inline void refresh(){size=siz(lc)+siz(rc)+1;}
 14 }*root[maxn];
 15 struct B{
 16     int id,a,b,c;
 17     bool operator<(const B &a)const{return this->a<a.a;}
 18 }a[maxn],b[maxn];
 19 void CDQ(int,int);
 20 void add(int,int);
 21 void del(int,int);
 22 int query(int,int);
 23 void insert(int);
 24 void erase(int);
 25 int rank(int);
 26 node *insert(node*);
 27 node *find(int);
 28 node *erase(node*);
 29 node *findmax(node*);
 30 void rebuild(node*);
 31 void zorder(node*);
 32 void removetree(node*);
 33 node *rebuild(int,int);
 34 int n,T,cnt,data[maxn];
 35 long long ans=0ll;
 36 int main(){
 37 #define MINE
 38 #ifdef MINE
 39     freopen("partial_order.in","r",stdin);
 40     freopen("partial_order.out","w",stdout);
 41 #endif
 42     scanf("%d",&n);
 43     for(int i=1;i<=n;i++)a[i].id=i;
 44     for(int i=1;i<=n;i++)scanf("%d",&a[i].a);
 45     for(int i=1;i<=n;i++)scanf("%d",&a[i].b);
 46     for(int i=1;i<=n;i++)scanf("%d",&a[i].c);
 47     CDQ(1,n);
 48     printf("%lld",ans);
 49 #ifndef MINE
 50     printf("\n-------------------------DONE-------------------------\n");
 51     for(;;);
 52 #endif
 53     return 0;
 54 }
 55 void CDQ(int l,int r){
 56     if(l>=r)return;
 57     int mid=(l+r)>>1;
 58     CDQ(l,mid);
 59     CDQ(mid+1,r);
 60     int i=l,j=mid+1,k=l;
 61     while(i<=mid&&j<=r){
 62         if(a[i]<a[j])b[k++]=a[i++];
 63         else b[k++]=a[j++];
 64     }
 65     while(i<=mid)b[k++]=a[i++];
 66     while(j<=r)b[k++]=a[j++];
 67     for(int i=l;i<=r;i++){
 68         a[i]=b[i];
 69         if(a[i].id<=mid)add(a[i].b,a[i].c);
 70         else ans+=query(a[i].b,a[i].c);
 71     }
 72     for(int i=l;i<=r;i++)if(a[i].id<=mid)del(a[i].b,a[i].c);
 73 }
 74 void add(int x,int d){
 75     while(x<=n){
 76         T=x;
 77         insert(d);
 78         x+=lowbit(x);
 79     }
 80 }
 81 void del(int x,int d){
 82     while(x<=n){
 83         T=x;
 84         erase(d);
 85         x+=lowbit(x);
 86     }
 87 }
 88 int query(int x,int d){
 89     int ans=0;
 90     while(x){
 91         T=x;
 92         ans+=rank(d);
 93         x-=lowbit(x);
 94     }
 95     return ans;
 96 }
 97 void insert(int x){
 98     node *rt=insert(new node(x));
 99     if(rt)rebuild(rt);
100 }
101 void erase(int x){
102     node *rt=erase(find(x));
103     if(rt)rebuild(rt);
104 }
105 int rank(int x){
106     node *rt=root[T];
107     int ans=0;
108     while(rt){
109         if(x<=rt->data)rt=rt->lc;
110         else{
111             ans+=siz(rt->lc)+1;
112             rt=rt->rc;
113         }
114     }
115     return ans;
116 }
117 node *insert(node *x){
118     if(!root[T]){
119         root[T]=x;
120         return NULL;
121     }
122     node *rt=root[T];
123     for(;;){
124         if(x->data<rt->data){
125             if(rt->lc)rt=rt->lc;
126             else{
127                 rt->lc=x;
128                 break;
129             }
130         }
131         else{
132             if(rt->rc)rt=rt->rc;
133             else{
134                 rt->rc=x;
135                 break;
136             }
137         }
138     }
139     x->prt=rt;
140     x=NULL;
141     for(;rt;rt=rt->prt){
142         rt->refresh();
143         if(max(siz(rt->lc),siz(rt->rc))>A*rt->size)x=rt;
144     }
145     return x;
146 }
147 node *find(int x){
148     node *rt=root[T];
149     while(rt){
150         if(x==rt->data)return rt;
151         else if(x<rt->data)rt=rt->lc;
152         else rt=rt->rc;
153     }
154     return NULL;
155 }
156 node *erase(node *x){
157     if(x->lc&&x->rc){
158         node *y=findmax(x->lc);
159         x->data=y->data;
160         return erase(y);
161     }
162     if(!x->lc&&!x->rc){
163         if(x->prt){
164             if(x==x->prt->lc)x->prt->lc=NULL;
165             else x->prt->rc=NULL;
166         }
167         else root[T]=NULL;
168     }
169     else if(x->lc&&!x->rc){
170         x->lc->prt=x->prt;
171         if(x->prt){
172             if(x==x->prt->lc)x->prt->lc=x->lc;
173             else x->prt->rc=x->lc;
174         }
175         else root[T]=x->lc;
176     }
177     else if(!x->lc&&x->rc){
178         x->rc->prt=x->prt;
179         if(x->prt){
180             if(x==x->prt->lc)x->prt->lc=x->rc;
181             else x->prt->rc=x->rc;
182         }
183         else root[T]=x->rc;
184     }
185     node *rt=x->prt;
186     delete x;
187     x=NULL;
188     for(;rt;rt=rt->prt){
189         rt->refresh();
190         if(max(siz(rt->lc),siz(rt->rc))>A*rt->size)x=rt;
191     }
192     return x;
193 }
194 node *findmax(node *x){
195     while(x->rc)x=x->rc;
196     return x;
197 }
198 void rebuild(node *rt){
199     cnt=0;
200     zorder(rt);
201     node *x=rebuild(1,cnt);
202     x->prt=rt->prt;
203     if(rt->prt){
204         if(rt==rt->prt->lc)rt->prt->lc=x;
205         else rt->prt->rc=x;
206     }
207     else root[T]=x;
208     removetree(rt);
209 }
210 void removetree(node *x){
211     if(!x)return;
212     removetree(x->lc);
213     removetree(x->rc);
214     delete x;
215 }
216 void zorder(node *x){
217     if(!x)return;
218     zorder(x->lc);
219     data[++cnt]=x->data;
220     zorder(x->rc);
221 }
222 node *rebuild(int l,int r){
223     if(l>r)return NULL;
224     int mid=(l+r)>>1;
225     node *x=new node(data[mid]);
226     x->lc=rebuild(l,mid-1);
227     if(x->lc)x->lc->prt=x;
228     x->rc=rebuild(mid+1,r);
229     if(x->rc)x->rc->prt=x;
230     x->refresh();
231     return x;
232 }

【后记】

这个题是用CDQ+树状数组水掉三维偏序之后的脑洞的产物……貌似在报复社会……

自己真是玩疯了……

时间: 2024-10-01 04:05:45

COGS 2479 偏序 题解的相关文章

COGS 2479. [HZOI 2016]偏序 [CDQ分治套CDQ分治 四维偏序]

传送门 给定一个有n个元素的序列,元素编号为1~n,每个元素有三个属性a,b,c,求序列中满足i<j且ai<aj且bi<bj且ci<cj的数对(i,j)的个数. 对于100%的数据,1<=n<=50000,保证所有的ai.bi.ci分别组成三个1~n的排列. $CDQ$分治套$CDQ$分治也不是很难嘛 对于本题,设四维$a,b,c,d$ $Sort\ at\ a$ $CDQ(l,r)$ $\quad CDQ(l,mid)$ $\quad CDQ(mid+1,r)$ $\

BZOJ3262:陌上花开 &amp; 洛谷3810:三维偏序——题解

两者题一样,方便没有bzoj权限的朋友. http://www.lydsy.com/JudgeOnline/problem.php?id=3262 https://www.luogu.org/problemnew/show/3810 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵

【教程】CDQ套CDQ——四维偏序问题【转载】

转自 前言 上一篇文章已经介绍了简单的CDQ分治,包括经典的二维偏序和三维偏序问题,还有带修改和查询的二维/三维偏序问题.本文讲介绍多重CDQ分治的嵌套,即多维偏序问题. 四维偏序问题       给定N(N<=20000)个有序四元组(a,b,c,d),求对于每一个四元组(a,b,c,d),有多少个四元组(a2,b2,c2,d2)满足a2<a && b2<b && c2<c && d2<d.        不需要太多思考,就能

COGS 1715 &amp; bzoj 3295 [CQOI2011]动态逆序对 题解

(又是一道树套树……自己真是玩疯了……) (题意略) 从网上也看过题解,好像解法很多……比如CDQ+树状数组,树状数组套主席树,树状数组套平衡树……我用的是树状数组套splay. (我会说是因为我不会写CDQ和树状数组套主席树么= =) (不得不吐槽,为啥splay这么快= =) 也没啥可说的,我写的是在线算法,只要在删除一个元素之前统计它前面比它大的数和后面比它小的数的个数(区间求和用树状数组,统计比它小/大的数的个数用平衡树写),把答案减掉对应数值即可. 鉴于这题卡常,我就加了快读和各种in

#COGS#1155. 最大乘积#啊,我怎么可能会写题解#可能充满误导和错误的解题过程。#

//写在前面:手抖,MinGW里删除汉字要两次.外加,参考了别人的写法,啊,好机智啊. 题面:一个正整数一般可以分为几个互不相同的自然数的和,如3=1+2,4=1+3,5=1+4=2+3,6=1+5=2+4,…. 现在你的任务是将指定的正整数n分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大. 输入是一个正整数n在3到10000之间,拆分之后累乘起来蛮大的要高精,然后long long只能过三个点,看那一大堆带﹣号的输出很吓人. 恩本来没仔细看题目,以为就是拆分然后乘积最大,于是就拆成

COGS 2188. [HZOI 2015] Math 题解

  题目描述: 给定n个数X1-Xn,求下面式子的值(整数部分): n<=107,xi<=109且互不相同. 分析: 其实一开始看见这道题我也吓傻了,k这么大,再说我又是数论鶸渣,打死也不会= = 后来看了各路神犇的题解,又仔细想了想,大概明白了. 首先,k这么大,已经不是高精乘和高精开方所能承受的了(当然,你也可以找个超级计算机算算试试) 所以我们可以把k视为∞(INF). 极限思想,由于xi互不相同,所以每个元素在比它稍微大一点点的数面前都是微乎其微,不会影响到整数部分的. (可以粗略验证

cogs 自己出的题目 题解报告

第一题很简单嘛,就是裸的动态树分治嘛 对于每一层的重心维护子树路径的信息和子树到上一层重心的点的信息 空间复杂度O(nlogn) 对于每一层我们按dis排序,之后记录军队数量的前缀和 查询的时候我们只需要在这一层二分既可以啦 感觉还是非常的easy呢 时间复杂度O(nlog^2n+mlog^2n) PS:原本题目并不是这个样子 原本是想出成有k个人在攻打城池u,问u需要坚持多少时间才能使得到来的军队人数总数>=k 这样我们就可以在外层二分一个时间,问题就转化成了这道题了(多了个log) 原本是想

COGS 08-备用交换机 题解——S.B.S.

8. 备用交换机 ★★   输入文件:gd.in   输出文件:gd.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] n个城市之间有通讯网络,每个城市都有通讯交换机,直接或间接与其它城市连接.因电子设备容易损坏,需给通讯点配备备用交换机.但备用交换机数量有限,不能全部配备,只能给部分重要城市配置.于是规定:如果某个城市由于交换机损坏,不仅本城市通讯中断,还造成其它城市通讯中断,则配备备用交换机.请你根据城市线路情况,计算需配备备用交换机的城市个数,及需配备备用交换

题解-luogu P3810三维偏序(陌上花开)

\(\rm三维偏序\) \(\rm一.定义:序列上每个点有三个权值~(x,y,z)~,求有多少个点对~(a,b)~同时满足~a_x \le b_x~,~a_y \le b_y~,~a_z \le b_z~\) \(\rm二.解法:~cdq~分治\) \(\rm\qquad首先,我们思考一下二维偏序的解法\) \(\rm\qquad\qquad我们先对整个序列按照~x~排一遍序,那么我们就已经解决了一个维度\) \(\rm\qquad\qquad即目前序列中所有后面的点的~x~值一定比前面的点小\