題意:給出一棵樹,(1)路徑加乙個值;(2)路徑上的節點的值反轉(只是值反轉,不是節點反轉);(3)詢問路徑最大值 最小值 和。
解題思路:
題目簡單,**冗長
寫這道題的時候還沒有學lct,所以我寫了一種非常奇葩的方法,純splay+樹鏈剖分,**冗長,但我覺得還挺好理解的。
首先我們可以先對整棵樹進行樹鏈剖分,分出輕重鏈之後就可以將一條鏈分解成若干條重鏈,用splay維護剖分出來的序列,查詢最大最小和sum都是splay的基礎操作就不說了,最關鍵的是進行樹鏈翻轉。這裡的確讓我為難了許久,後來我奇葩的想出了乙個辦法::將鏈按順序提取出來合併然後進行反轉再拆開按順序放回去,這樣就可以做到下一次查詢這裡正好是反過來的了,然後就是怎麼做的問題了,這裡的確**,為了不改變點在序列的位置方便提取,我先按照這些條鏈在序列中從後往前提取,最後還要從前往後放回去,不過這裡處理完之後就問題不大了,看著**都是淚啊!!!
(**核能,想看的話請做好心理準備)
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct splay
*null=new splay(2000209123),*root,*midroot,*swz[100005];
long
long t;
long
long pou[100000];
long
long fir[100005];
long
long nex[100005];
long
long wz[100000];
struct point
a[100005];
struct bian
b[100005];
void dfs1(int u,int fro)
}}void dfs2(int u,int fro)
}splay :: splay(long
long x)
void splay :: add(long
long x)
void splay :: rev()
void splay :: push_up()
void splay :: push_down()
if(lazy_mark)
}void left(splay *x)
void right(splay *x)
void splaying(splay *x,splay *goal)
if(x==y->ls)
else
}x->push_up();
}void my_find(splay *x,long
long mc,splay *z)
}splaying(x,z);
midroot=x;
}void add()
if(a[x].deepnull);
my_find(root,wz[x]+2,root);
root->rs->ls->add(v);
root->rs->push_up();
root->push_up();
}splay* maketree(long
long l,long
long r)
void init()
int find_lca(int x,int y)
void my_merge(splay* x,splay* y)
splay* tiqu(int l,int r,splay* &o)
struct tiquchulaide
midd[50000];
bool cmp1(tiquchulaide a,tiquchulaide b)
bool c***(tiquchulaide a,tiquchulaide b)
y_find(a[a[y].top].fa,lca);
shou[++top]=wz[a[y].top];
len[top]=wz[y]-wz[a[y].top]+1;
midd[top].num=top;
midd[top].shou=shou[top];
midd[top].len=len[top];
}void fanzhuanqujian()
shou[++top]=wz[a[x].top];
len[top]=wz[x]-wz[a[x].top]+1;
midd[top].num=top;
midd[top].shou=shou[top];
midd[top].len=len[top];
x=a[a[x].top].fa;
}jilu=top;
if(x==lca)
y_find(y,lca);
sort(midd+1,midd+1+top,cmp2);
for(int i=1;i<=top;i++)
sort(midd+1,midd+1+top,cmp1);
midroot=null;
for(int i=1;i<=top;i++)
//coutrev();
for(int i=1;i<=top;i++)
sort(midd+1,midd+1+top,c***);
for(int i=1;i<=top;i++)
}void
sum()
if(a[x].deepnull);
my_find(root,wz[x]+2,root);
ans+=root->rs->ls->sum;
printf("%lld\n",ans);
}void major()
if(a[x].deepnull);
my_find(root,wz[x]+2,root);
if(root->rs->ls->maxx>maxx) maxx=root->rs->ls->maxx;
printf("%lld\n",maxx);
}void minor()
if(a[x].deepnull);
my_find(root,wz[x]+2,root);
if(root->rs->ls->minnrs->ls->minn;
printf("%lld\n",minn);
}char s[10];
int main()
int t=rand()%n+1;
dfs1(t,0);
dfs2(t,0);
init();
//for(int i=1;i<=t;i++) coutreturn
0;}
Splay括號匹配(BZOJ2209)
time limit 20 sec memory limit 259 mb submit 894 solved 423 submit status 輸入資料的第一行包含兩個整數n和q,分別表示括號序列的長度,以及操作的個數。第二行包含乙個長度為n的括號序列。接下來q行,每行三個整數t x和y,分別表...
bzoj 3786 星系探索 splay
bzoj真是坑爹,本地跑的差不多的程式,指標比陣列快到不知道 去了。然後我就開始了艱辛的卡常數,最終比很多指標快多辣 由於有子樹移動,那麼考慮維護括號序列。也就是dfs入棧為 出棧為 然後 為正的權值。那麼子樹移動相當於平衡樹的 和合併。用splay實現。ps 求卡常數大神優化 ac 如下 目前最快...
BZOJ2329 括號修復(Splay)
bzoj 洛谷本來想著用線段樹來寫 但是有乙個區間翻轉 所以不能用線段樹了,就只能用平衡樹 然後直接sp lay 就好了 注意一下幾個標記的下放問題 這種資料結構真的沒有什麼思路可言。include include include include include include include in...