CDQパーティションの研究ノート(非教育)
(非フルバージョンは、より多くなるため)
- 何というパーティションをCDQ?
CDQパーティションは、規模間二つに大きな問題であるそのサブ問題の半分に対する答えであり、統計アルゴリズムの二つのサブ問題、複雑$ nklogn $
- 書き方のCDQパーティション?
コードの例を参照してください
- CDQパーティションは行うことができますか?
私の現在の理解では、CDQパーティションは、そのようなだけで、それは転送の地点にあるよりも、プロパティの数が少ないから解答上の点として、いくつかの部分的な受注と関連トピックを、解決するために使用され、その後、あなたは使用することができます答えを更新するCDQパーティション
推奨トピック:
T1。
CDQパーティション・テンプレートのタイトル、プリチーズ:CDQ分割統治、フェンウィックツリー
//I love Nanami Chiaki
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
const int maxn=1e5+7;
int n,k;
int ans[maxn],res[maxn];
int dat[maxn<<1];
bool hve[maxn];
struct Flower{
int a,b,c,id;
}f[maxn],t[maxn];
inline bool cmp1(Flower X,Flower Y){
return (X.a^Y.a)?(X.a<Y.a):((X.b^Y.b)?(X.b<Y.b):(X.c<Y.c));
}
inline void add(int p,int v){
while (p<=k){
dat[p]+=v;
p+=lowbit(p);
}
}
inline int sum(int p){
int re=0;
while (p){
re+=dat[p];
p-=lowbit(p);
}
return re;
}
void cdq1(int l,int r){
if (l==r) return;
int mid=(l+r)>>1;
cdq1(l,mid);
cdq1(mid+1,r);
int i=l,j=mid+1,sz=l;
while (i<=mid || j<=r){
if (i>mid){
t[sz++]=f[j];
ans[f[j].id]+=sum(f[j].c);
j++;
}
else if (j>r || f[i].b<=f[j].b){
t[sz++]=f[i];
hve[f[i].id]=true;
add(f[i++].c,1);
}
else{
t[sz++]=f[j];
ans[f[j].id]+=sum(f[j].c);
j++;
}
}
for (int i=l;i<=r;i++){
f[i]=t[i];
if (hve[f[i].id]){
hve[f[i].id]=false;
add(f[i].c,-1);
}
}
}
int main(){
scanf("%d%d",&n,&k);
for (int i=0;i<n;i++){scanf("%d%d%d",&f[i].a,&f[i].b,&f[i].c);f[i].id=i;}
sort(f,f+n,cmp1);
int prea=-1,preb=-1,prec=-1,num=0;
for (int i=n;i>=0;i--){
if (f[i].a==prea && f[i].b==preb && f[i].c==prec) ans[f[i].id]=num++;
else{
prea=f[i].a;preb=f[i].b;prec=f[i].c;num=1;
}
}
cdq1(0,n-1);
for (int i=0;i<n;i++) res[ans[i]]++;
for (int i=0;i<n;i++) printf("%d\n",res[i]);
return 0;
}
問題/ライトプログラムに、独自の解決策について何かを言うとき見て困惑
なぜあなたは右で書くのですか?
それは、最も直感的なIの疑いで後は、しばらくの間、私は答えを得たと思いました。
主な機能には、我々は、プロパティは(答えの数はバックの前に番号を更新するためになされなければならないことを保証する、(慎重sort関数CMPで見てBを見つけるだろうし、配列決定する必要がC)注文したことを確認する必要があります番号は、以前の番号を更新するために戻って行くことができない?特殊なケースがある、と言って数分待つ)、これはおそらく基礎CDQの分割統治です。
その後cdq1機能、我々最初の分割統治、
かかわらず、治療前の、質問を聞いているようだが、私は会っていないような気がします、すべての後、私は唯一の2タイトルを働きましたループはそのリターンを発見しながら、慎重に観察をfの配列をソート属性bの結果に基づいてであることが判明し、このビーイング非常に素晴らしい場所があります。このような子供は順序それからではないでしょうか?オーダー外となりますが、内部プロセスの間に更新された二つのサブの答えの間には関係が終了していない、と私たちは順番を超える行を開始するため、子の間に更新され、残りは目の前ので、質問に答えますより多くの属性を満たすかの手段オーダーのうちの両方が、小さな問題や同等の前の子よりも、特定の問題の背後にある子の二つのサブ問題たとえその少数の裏に等しくなければなりません。
整然と合併B二つのサブ質問この時間は、最初のC = Kサブ問題のアレイの前に木と小さな新しいシーケンス行くをマージする過程でB、および保守を追加すると、同時に数であります問題のある子の後ろの各点について、彼の答えは、樹状配列cの数は、アレイ内の木の数がBのそれよりも小さくなければならないためである(それにその数よりも小さく、追加します)私が理由の前に言ったように、それは、よりも小さいと、(それがより早くより添加ので)。
あなたの楽曲名を、時間を節約するために、私はまた、問題を解決するためのエラーが発生しやすい箇所を書きました
- = AJ、BI = BJ、CI = iがjを目の前に来た場合でも、時間CJ aiをすると、私は更新することができjは、その後、我々はコードを参照してください、ライン上でそれを、この特定のケースを処理する必要があります
T2
私はその質問に渡すことができませんでしたので、この質問は、名前の拡張バージョンを書き込むためのデータが弱すぎるされていない理由
フロントチーズ:CDQ分割統治、フェンウィックツリー
バージョン1:TLEバージョン(CDQセットCDQ)
//I love Nanami Chiaki
#include<bits/stdc++.h>
using namespace std;
const int maxn=500007;
const int maxp=1000007;
const int inf=1e9+7;
inline int read(){
int re=0;char c=getchar();
while (c<'0' || c>'9') c=getchar();
while (c>='0' && c<='9'){re=(re<<1)+(re<<3)+(c^48);c=getchar();}
return re;
}
struct Node{int x,y,t,op,f1;}hve[maxn<<1],hve1[maxn<<1],hve2[maxn<<1];
int n,m,mm=0,ans[maxn];
inline bool cmp(Node X,Node Y){return (X.x^Y.x)?(X.x<Y.x):((X.y^Y.y)?(X.y<Y.y):(X.t<Y.t));}
void solveit2(int l,int r){
if (l==r) return;
int mid=(l+r)>>1;
solveit2(l,mid);
solveit2(mid+1,r);
int i=l,j=mid+1,sz=l,mx=-inf;
while (i<=mid || j<=r){
if (i>mid){
if (hve1[j].op && hve1[j].f1) ans[hve1[j].op]=min(hve1[j].x+hve1[j].y-mx,ans[hve1[j].op]);
hve2[sz++]=hve1[j++];
}
else if (j>r || hve1[i].t<hve1[j].t){
if (!hve1[i].op && !hve1[i].f1) mx=max(mx,hve1[i].x+hve1[i].y);
hve2[sz++]=hve1[i++];
}
else{
if (hve1[j].op && hve1[j].f1) ans[hve1[j].op]=min(hve1[j].x+hve1[j].y-mx,ans[hve1[j].op]);
hve2[sz++]=hve1[j++];
}
}
for (int i=l;i<=r;++i) hve1[i]=hve2[i];
}
void solveit1(int l,int r){
if (l==r) return;
int mid=(l+r)>>1;
solveit1(l,mid);
solveit1(mid+1,r);
int i=l,j=mid+1,sz=i;
while (i<=mid || j<=r){
if (i>mid){hve1[sz++]=hve[j++];hve1[sz-1].f1=1;}
else if (j>r || (hve[i].y<hve[j].y || (hve[i].y==hve[j].y && hve[i].t<hve[j].t))){hve1[sz++]=hve[i++];hve1[sz-1].f1=0;}
else{hve1[sz++]=hve[j++];hve1[sz-1].f1=1;}
}
for (int i=l;i<=r;++i) hve[i]=hve1[i];
solveit2(l,r);
}
int main(){
n=read();m=read();
for (int i=0;i<n;++i){int x=read(),y=read();hve[i].x=x;hve[i].y=y;hve[i].t=0;hve[i].op=0;}
for (int j=0;j<m;++j){
int T=read(),x=read(),y=read();hve[n+j].x=x;hve[n+j].y=y;hve[n+j].t=j+1;
if (T==1) hve[n+j].op=0;
else{hve[n+j].op=++mm;ans[mm]=inf;}
}
n+=m;m=mm;
for (int k=0;k<4;++k){
sort(hve,hve+n,cmp);
solveit1(0,n-1);
for (int j=0;j<n;++j){swap(hve[j].x,hve[j].y);hve[j].x=maxp-6-hve[j].x;}
}
for (int i=1;i<=m;++i) printf("%d\n",ans[i]);
return 0;
}
バージョン2:AC版(CDQセットフェンウィック木)醜い((なぜ我慢しないで(もプラス何かで、ヘッダのシリーズで開始するファイルの#pragma GCCは手動恥ずかしいオーバー最適化することができますか))?アップ!)
確認するにはACに提出私のレコードを(交互理由は、あまりにも多くの大提出が限られているので、大きくはない、と再び恥ずかしいマニュアル)
//I love Nanami Chiaki
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
const int maxn=300007;
const int maxp=1000007;
const int inf=1e9+7;
inline int read(){
int re=0;char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)){re=(re<<1)+(re<<3)+(c^48);c=getchar();}
return re;
}
struct Node{int x,y,t,op;bool ff;}hve[maxn<<1],hve1[maxn<<1];
int n,m,mm=0,ans[maxn],dat[maxn];
inline bool cmp(Node X,Node Y){return (X.x^Y.x)?(X.x<Y.x):((X.y^Y.y)?(X.y<Y.y):(X.t<Y.t));}
inline void mymax(int &x,int y){if (x<y) x=y;}
inline void mymin(int &x,int y){if (x>y) x=y;}
inline void myswap(int &x,int &y){int t=x;x=y;y=t;}
inline void add(int p,int v){while (p<=m && dat[p]<v){mymax(dat[p],v);p+=lowbit(p);}}
inline int query(int p){int re=0;while (p){mymax(re,dat[p]);p-=lowbit(p);}return (re==0)?-inf:re;}
inline void clear(int p){while (p<=m && dat[p]){dat[p]=0;p+=lowbit(p);}}
void solveit1(int l,int r){
if (l==r) return;
int mid=(l+r)>>1;
solveit1(l,mid);
solveit1(mid+1,r);
int i=l,j=mid+1,sz=i;
while (i<=mid || j<=r){
if (i>mid){if (hve[j].op) mymin(ans[hve[j].op],hve[j].x+hve[j].y-query(hve[j].t));hve1[sz++]=hve[j++];}
else if (j>r || (hve[i].y<hve[j].y || (hve[i].y==hve[j].y && hve[i].t<hve[j].t))){if (!hve[i].op) add(hve[i].t+1,hve[i].x+hve[i].y);hve1[sz++]=hve[i++];hve1[sz-1].ff=true;}
else{if (hve[j].op) mymin(ans[hve[j].op],hve[j].x+hve[j].y-query(hve[j].t));hve1[sz++]=hve[j++];}
}
for (int i=l;i<=r;++i){
if (hve1[i].ff){clear(hve1[i].t+1);hve1[i].ff=false;}
hve[i]=hve1[i];
++i;if (i>r) break;
if (hve1[i].ff){clear(hve1[i].t+1);hve1[i].ff=false;}
hve[i]=hve1[i];
}
}
int main(){
n=read();m=read();
int x,y,T;
for (int i=0;i<n;++i){x=read();y=read();hve[i].x=x;hve[i].y=y;hve[i].t=0;hve[i].op=0;}
for (int j=0;j<m;++j){
T=read();x=read();y=read();hve[n+j].x=x;hve[n+j].y=y;hve[n+j].t=j+1;
if (T==1) hve[n+j].op=0;
else{hve[n+j].op=++mm;ans[mm]=inf;}
}
n+=m;
for (int k=0;k<4;++k){
sort(hve,hve+n,cmp);
solveit1(0,n-1);
for (int j=0;j<n;++j){
myswap(hve[j].x,hve[j].y);hve[j].x=maxp-6-hve[j].x;
++j;if (j>=n) break;
myswap(hve[j].x,hve[j].y);hve[j].x=maxp-6-hve[j].x;
}
}
for (int i=1;i<=mm;++i) printf("%d\n",ans[i]);
return 0;
}
この質問はおそらく考えています:
もちろん、私も問題の解決策を参照して、最初に完全に問題CDQなっを感じませんでした、しかし、探し内部の問題CDQテーブルです。
この質問は、あなたがタイムスタンプを設置し、各クエリ点のために、実際には、我々はそれの前とタイムスタンプのx +ポイントで左下隅にある計算された各ポイントとポイントのクエリに使用できるという考えでありますその上で、yの最大値は、答えは分(XI + XJ-MX)で、これは当然のことながら、右上、右下、間違っているだけでなく、左上である、などいくつかの方向が、位置は左下隅と行くと本質的に似ていますその後、問題は各クエリ点に対して4倍に依頼する形質転換されるライン上のBEG(実際には、それにマップクリックを消す)、私だけのx <= XI、Y <= YI、Tポイント<tiが唯一です問題は、問題とそれではない外観を更新することができます
バージョン1:
私は、すべての後に、以前のソリューションは、4次元の半順序の問題、間違った問題で、この方法の使用の成功の結果を解決することはできませんCDQ CDQセットについて学ぶためにこの質問を使用していました
しかし、まだそれについて話
- CDQは、このCDQのように設定されています
- 最初のステップは、並べ替えに従いました
- そして、最初のパーティションにまたはsolve1で、その後に対処するためにBに従ってソートが、今回は、私たちは、他のデータ構造でメンテナンスを考慮していません。その後、我々は、サブ問題の数は、サブ問題の数は添字1をプレイした後、添字は(番号0が1に解答のインデックス番号を更新するために使用することができ表し、添字0を再生前方に置くことができます)プロパティの意味で
- その後、我々はまあBの属性に応じてソートする必要があり、我々はsolve2を入力します。
- solve2では、我々はまだパーティションの問題に対処する必要があり、我々は唯一の更新添字に0のインデックス番号を使用するようにsolve1このパーティションは、二つの副問題との答えを処理するために使用されていることを知っています数1、パーティションプロセス、solve2数1の答えとしてマークsolve2が更新された後、ループ処理が0からの質問の下の子供に番号でsolve2サブ問題の前にマークされている間(2つのサブsolve2分割統治理由その後、質問、それらの中に、このようなを更新答えが完成し、処理を持っている)、Cのマージソートに従い、合わせbを開始配列solve2が注文したことから、サブ問題の前に属性bの数はリアサブ問題の属性bより小さくなければなりません場合、マージプロセスcにおいて、数が数のMXの前に更新することができ、Cの属性は、それよりも小さくなければなりません。そしてその後、更新MX、(サブ問題後)MX更新されたインデックス番号1、問題なしに数0(前のサブ問題)で標識しました
- 約4次元部分プロセスシーケンスは、おそらく最初に注文して、配置された0/1 B整然としたケースに入れ、その後、B 0/1にに、あること、同じです状況下で、cはそれに整然とした、最後に更新答えに配置されました
バージョン2:
カードが多いカード死んだああ!!!、不快
私は/使用が多いいくつかのカードのトリックを学びます
ループ展開、新しい学校は、私はまた、Baiduのではなく、自分のBaiduは、かなり良い感じ
カスタムMAX、MIN、スワップ
シンプルで速読
前にあるDuitouファイル(ヘルプを私は半分の時間を最適化し、恥ずかしいマニュアル)
以上であるために