洛谷 P3920 WC2014 紫荊花之戀

2022-05-26 22:57:10 字數 3312 閱讀 3988

傳送門

想題5分鐘,調題20小時\(qaq\)

我做這題的歷程:

這什麼破玩意兒

如果您聽說過「替罪羊式重構點分樹」的話這題就很好了。

首先考慮樸素的點分治:

每次分治統計路徑經過分治中心的點對的貢獻。

記\(dis_i\)為點\(i\)到分治中心的距離,條件即\(dis_i+dis_j\le r_i+r_j\)。

移個項:\(dis_i-r_i\le r_j-dis_j\)。

把\(r_i-dis_i\)插進平衡樹里,查詢平衡樹中大於等於\(dis_i-r_i\)的數量。

動態的做法就很明顯了,點分樹上每個點開個平衡樹。還要容斥減掉同一子樹的貢獻,用\(vector\)記錄每層上用於容斥的平衡樹。

加點直接在點分樹上將\(i\)與\(a_i\)連邊,暴力跳點分樹在平衡樹里查,並把自己的資訊插進去。

注意到每次都會在某個點下方掛乙個點,而點分樹的樹高要維持在\(\log\)級別。

很像平衡樹。旋轉是不可能了,利用替罪羊樹的思想重構點分樹。

記\(siz\)為點分樹上子樹大小。當\(\max\limits_siz_i\ge siz_x\times \alpha\)(\(\alpha\)為平衡因子,我定的\(0.7\))就重構點\(i\)的子樹。

\(asuldb\):重構多簡單,不就點分治一下嗎。

重構我們要幹啥(\(x\)為待重構點):

為了保證單次重構複雜度是\(o(siz_x\log siz_x)\)的,把子樹資訊提出來排個序直接build。\(treap\)有隨機權值不好build,\(splay\)太慢於是選擇替罪羊樹。

(其實假了,還有個排序重構是\(o(siz_x\log^2 siz_x)\)的。。。)

還要帶加點查詢點對的距離,可以倍增,我用的\(lct\)。

複雜度為\(o(n\log^2 n)\)。

注意垃圾**。

全是細節的**:

#include #include #include #include #include #include #include #define maxn 100005

#define inf 0x3f3f3f3f

const double alpha = 0.7;

const int mod = 1e9;

using namespace std;

inline int read()

while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();

return y?-x:x;

}struct edgee[maxn<<1];

struct scapegoattree

void build(int *base,int l,int r,int &node)

node=pool[cnt--];

int mid=l+r>>1;

dat[node]=base[mid];

build(base,l,mid-1,ls(node));

build(base,mid+1,r,rs(node));

siz[node]=siz[ls(node)]+siz[rs(node)]+1;

}void dfs(int node)

int push(int &node,int d)

++siz[node];

int p=push(son(node,dat[node]=x)ans+=siz[rs(node)]+1,node=ls(node);

else node=rs(node);

}return ans;

}scapegoattree()

}sgt;

struct linkcuttree

inline void addedge(int s,int f,int wh)

inline void reverdown(int node)

inline void pushdown(int node)

void zhuan(int x)

void splay(int x)

}void access(int x)

void makeroot(int x)

void link(int x,int y)

int get(int x,int y)

}lct;

int r1[maxn],r2[maxn],h[maxn],siz[maxn],ts[maxn],pool[maxn<<2],num,cnt=(maxn<<2)-1,all,mx,root,l1,l2;

int mp[maxn],rt[maxn],exc[maxn<<3],line[maxn],dep[maxn],fa[maxn],a[maxn];

bool vis[maxn],rub[maxn<<1];

vectorb[maxn];

setson[maxn];

inline void add(int from,int to,int l)

void getroot(int node,int f=0)

ma=max(ma,all-siz[node]);

if(ma::iterator iter=son[x].begin();iter!=son[x].end();++iter)

dep[line[++tail]=*iter]=dep[x]+1;

while(dep[x]--)

sgt.clear(rt[x]);

son[x].clear();

}for(register int i=rc+1;i<=cnt;++i)rub[pool[i]]=0;

}void dfs(int node,int len,int f)

}void build(int node)

sort(r1+1,r1+1+l1);

sgt.build(r1,1,l1,rt[node]);

for(register int i=h[node];i;i=e[i].pre)

}void rebuild(int node)

if(p)

}int main()

printf("%lld\n",ans);

rebuild(i);}}

洛谷P2014 選課

題目描述 在大學裡每個學生,為了達到一定的學分,必須從很多課程裡選擇一些課程來學習,在課程裡有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有n門功課,每門課有個學分,每門課有一門或沒有直接先修課 若課程a是課程b的先修課即只有學完了課程a,才能學習課程b 乙個學生要從這些課程...

洛谷P2014 選課

又是一道樹型dp,不過這次是以點帶權值,因為根是不確定的,我們可以設個虛根 0 因為算是多了一點,所以總點數應該 因為是點帶權值,所以不用dfs邊的數量了,不過有一點虛注意,因為多了乙個點,所以j層迴圈 所選的邊數 下界應該是到2的。include include using namespace s...

洛谷P2014 選課

題目描述 在大學裡每個學生,為了達到一定的學分,必須從很多課程裡選擇一些課程來學習,在課程裡有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有n門功課,每門課有個學分,每門課有一門或沒有直接先修課 若課程a是課程b的先修課即只有學完了課程a,才能學習課程b 乙個學生要從這些課程...