日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

【WC2014】紫荆花之恋【替罪羊思想】【动态点分树】【替罪羊树】

發(fā)布時(shí)間:2023/12/3 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【WC2014】紫荆花之恋【替罪羊思想】【动态点分树】【替罪羊树】 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

傳送門(mén)

題意:有一棵開(kāi)始時(shí)沒(méi)有結(jié)點(diǎn)的樹(shù),nnn次詢(xún)問(wèn),每次新加一點(diǎn)并給定父結(jié)點(diǎn)、到父親的距離、參數(shù)rir_iri?,并詢(xún)問(wèn)滿(mǎn)足dist(u,v)≤ru+rvdist(u,v)\leq r_u+r_vdist(u,v)ru?+rv?的點(diǎn)對(duì)(u,v)(u,v)(u,v)的對(duì)數(shù)。

n≤105n\leq 10^5n105,強(qiáng)制在線(xiàn)

很好的一道題,并沒(méi)有江湖上傳言的那么恐怖我只寫(xiě)了兩天而已

顯然我們只需要考慮新加的點(diǎn)的貢獻(xiàn)和之前加起來(lái)即可

設(shè)當(dāng)前加的點(diǎn)為uuu

盯著這個(gè)式子:

dist(u,v)≤ru+rvdist(u,v)\leq r_u+r_vdist(u,v)ru?+rv?

如果我們隨便找到uuuvvv路徑上的一點(diǎn)ppp ,可以拆成

dist(u,p)+dist(v,p)≤ru+rvdist(u,p)+dist(v,p)\leq r_u+r_vdist(u,p)+dist(v,p)ru?+rv?

我們要求的就是滿(mǎn)足

dist(v,p)?rv≤ru?dist(u,p)dist(v,p)-r_v\leq r_u-dist(u,p)dist(v,p)?rv?ru??dist(u,p)

vvv的個(gè)數(shù)

如果ppp固定,就可以用平衡樹(shù)瞎維護(hù)一下

然后可以枚舉uuu的祖先作為ppp統(tǒng)計(jì)答案

但顯然給條鏈就掛了

注意到我們這樣做的復(fù)雜度是O(u的深度)O(u的深度)O(u),可以試試點(diǎn)分樹(shù)

如果樹(shù)的形態(tài)是固定的,因?yàn)辄c(diǎn)分樹(shù)的性質(zhì)

點(diǎn)分樹(shù)上兩點(diǎn)的lcalcalca在原樹(shù)上這兩點(diǎn)的路徑上

并且我們上面要求的恰好只是在路徑上,所以可以在點(diǎn)分樹(shù)上用相同的方式統(tǒng)計(jì)

具體實(shí)現(xiàn)的時(shí)候,每個(gè)點(diǎn)分樹(shù)上的結(jié)點(diǎn)uuu開(kāi)棵平衡樹(shù)記錄子樹(shù)中所有點(diǎn)vvvdist(v,u)?rvdist(v,u)-r_vdist(v,u)?rv?

然后設(shè)新加的點(diǎn)為xxx,從xxx開(kāi)始往上跳,跳到uuu時(shí)詢(xún)問(wèn)uuu的平衡樹(shù)中≤rx?dist(x,u)\leq r_x-dist(x,u)rx??dist(x,u)的點(diǎn)的個(gè)數(shù)

但這樣會(huì)算進(jìn)不是簡(jiǎn)單路徑的,所以需要記錄uuu的 某個(gè)兒子 的子樹(shù) 中的結(jié)點(diǎn)vvvdist(v,u)?rvdist(v,u)-r_vdist(v,u)?rv?的信息減一下

具體而言就是每個(gè)結(jié)點(diǎn)uuu再開(kāi)一個(gè)平衡樹(shù)記錄子樹(shù)中的每個(gè)結(jié)點(diǎn)vvvdist(v,fau)?rvdist(v,fa_u)-r_vdist(v,fau?)?rv?

但是這棵樹(shù)還會(huì)動(dòng)

采用黑科技,用替罪羊樹(shù)的思想,在跳點(diǎn)分樹(shù)的時(shí)候如果有偏得太嚴(yán)重的點(diǎn),就把整個(gè)子樹(shù)重構(gòu)

說(shuō)著簡(jiǎn)單其實(shí)細(xì)節(jié)不少

因?yàn)槌?shù)大得驚人,所以?xún)?nèi)部平衡樹(shù)用了替罪羊樹(shù)

真·奧義·替罪羊套替罪羊

復(fù)雜度O(能過(guò))O(能過(guò))O(過(guò))

本題的易錯(cuò)細(xì)節(jié):

  • 內(nèi)部替罪羊重構(gòu)的時(shí)候要清空chchch數(shù)組
  • 點(diǎn)分樹(shù)重構(gòu)子樹(shù)的時(shí)候在原樹(shù)上只是一個(gè)連通塊,需要dfs一遍打個(gè)標(biāo)記,后面只訪問(wèn)有標(biāo)記的點(diǎn)
  • 點(diǎn)分樹(shù)重構(gòu)子樹(shù)時(shí)要清空所有結(jié)點(diǎn)的一堆信息
  • 因?yàn)橐?span id="ozvdkddzhkzd" class="katex--inline">distdistdist,在點(diǎn)分樹(shù)重構(gòu)前要先把新的子樹(shù)的根(即整個(gè)連通塊的重心)的父親接上
  • 要記錄點(diǎn)分樹(shù)上每個(gè)點(diǎn)是父親的第幾個(gè)兒子并傳引用
  • 在點(diǎn)分樹(shù)重構(gòu)時(shí)暴力建平衡樹(shù)要開(kāi)兩個(gè)vector并分別排序
  • 點(diǎn)分樹(shù)重構(gòu)不能修改up,disup,disup,dis等信息
  • 判斷重構(gòu)時(shí)要特判是整個(gè)點(diǎn)分樹(shù)的根的情況
  • 要寫(xiě)內(nèi)存回收池
  • #include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <vector> #include <algorithm> #include <cassert> #define MAXN 100005 #define MAXM 200005 using namespace std; const int MOD=1e9; const double alpha=0.8; typedef long long ll; struct edge{int u,v,w;}e[MAXM]; int head[MAXN],nxt[MAXM],cnt; inline void addnode(int u,int v,int w) {e[++cnt]=(edge){u,v,w};nxt[cnt]=head[u];head[u]=cnt; } inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } int dis[MAXN],dep[MAXN],up[MAXN][20]; inline int lca(int x,int y) {if (dep[x]<dep[y]) swap(x,y);int t=dep[x]-dep[y];for (int i=0;(1<<i)<=t;i++) if (t&(1<<i)) x=up[x][i];if (x==y) return x;for (int i=19;i>=0;i--) if (up[x][i]!=up[y][i]) x=up[x][i],y=up[y][i];return up[x][0]; } inline int dist(const int& x,const int& y){return dis[x]+dis[y]-2*dis[lca(x,y)];} namespace SGT {int *pos;const int N=MAXN<<6;int bin[N],lis[N];int ch[N][2],siz[N],val[N],tot;inline int newnode(const int& v){int x=(bin[0]? bin[bin[0]--]:++tot);return ch[x][0]=ch[x][1]=0,siz[x]=1,val[x]=v,x;}inline void update(const int& x){siz[x]=siz[ch[x][0]]+1+siz[ch[x][1]];}void insert(int& x,int v){if (!x) return (void)(x=newnode(v));insert(ch[x][v>val[x]],v);update(x);if (siz[ch[x][0]]>siz[x]*alpha||siz[ch[x][1]]>siz[x]*alpha) pos=&x;}void build(int& x,int l=1,int r=lis[0]){if (l>r) return (void)(x=0);int mid=(l+r)>>1;x=newnode(lis[mid]),build(ch[x][0],l,mid-1),build(ch[x][1],mid+1,r),update(x);}void dfs(int& x){if (!x) return;dfs(ch[x][0]);bin[++bin[0]]=x,lis[++lis[0]]=val[x];dfs(ch[x][1]);x=0;}inline void rebuild(){if (pos==NULL) return;lis[0]=0,dfs(*pos),build(*pos),pos=NULL;}inline void modify(int& x,int v){insert(x,v),rebuild();}int query(int x,int v){if (!x) return 0;if (v<val[x]) return query(ch[x][0],v);return siz[ch[x][0]]+1+query(ch[x][1],v);}inline void getbuf(const vector<int>& v){lis[0]=0;for (int i=0;i<(int)v.size();i++) lis[++lis[0]]=v[i];} } using SGT::modify; using SGT::query; using SGT::getbuf; int fa[MAXN],idx[MAXN],rt[MAXN],prt[MAXN],r[MAXN],*pos; int Rt=1; vector<int> son[MAXN],sub[MAXN]; inline void addnode(int u,int f){fa[u]=f,son[f].push_back(u),idx[u]=son[f].size()-1;} inline int insert(int x) {int ans=0;for (int u=x,v=0;u;v=u,u=fa[u]){int val=r[x]-dist(x,u);ans+=query(rt[u],val)-query(prt[v],val);modify(rt[u],-val);if (v) modify(prt[v],-val);if (SGT::siz[rt[v]]>SGT::siz[rt[u]]*alpha) pos=(fa[u]? &son[fa[u]][idx[u]]:&Rt);}return ans; } bool vis[MAXN]; vector<int> block; void dfs(int u){vis[u]=1,block.push_back(u);for (int i=0;i<(int)son[u].size();i++) dfs(son[u][i]);} int siz[MAXN],maxp[MAXN]={0x7fffffff},root; void findrt(int u,int f,int sum) {siz[u]=1,maxp[u]=0;for (int i=head[u];i;i=nxt[i])if (vis[e[i].v]&&e[i].v!=f){findrt(e[i].v,u,sum);siz[u]+=siz[e[i].v],maxp[u]=max(maxp[u],siz[e[i].v]);}if (sum-siz[u]>maxp[u]) maxp[u]=sum-siz[u];if (maxp[u]<maxp[root]) root=u; } int getsiz(int u,int f) {int ans=1;for (int i=head[u];i;i=nxt[i])if (vis[e[i].v]&&e[i].v!=f)ans+=getsiz(e[i].v,u);return ans; } void build() {vis[root]=0;int u=root;sub[u].push_back(u);for (int i=head[u];i;i=nxt[i])if (vis[e[i].v]){root=0;findrt(e[i].v,0,getsiz(e[i].v,0));int v=root;addnode(v,u);build();for (vector<int>::iterator it=sub[v].begin();it!=sub[v].end();++it) sub[u].push_back(*it);}vector<int> tmp1,tmp2;for (int i=0;i<(int)sub[u].size();i++){int v=sub[u][i];tmp1.push_back(dist(v,u)-r[v]);tmp2.push_back(dist(v,fa[u])-r[v]);}sort(tmp1.begin(),tmp1.end());getbuf(tmp1),SGT::build(rt[u]);if (fa[u]){sort(tmp2.begin(),tmp2.end());getbuf(tmp2),SGT::build(prt[u]);} } int main() {read();int n=read();ll lans=0;for (int u=1;u<=n;u++){int a,c;a=read()^(lans%MOD),c=read(),r[u]=read();up[u][0]=a;for (int i=1;i<20;i++) up[u][i]=up[up[u][i-1]][i-1];dis[u]=dis[up[u][0]]+c,dep[u]=dep[up[u][0]]+1;if (u>1) addnode(u,a);addnode(u,a,c),addnode(a,u,c);printf("%lld\n",lans+=insert(u));if (pos==NULL) continue; // cerr<<"rebuild "<<*pos<<'\n';int f=fa[*pos],id=idx[*pos];dfs(*pos),root=0,findrt(*pos,0,SGT::siz[rt[*pos]]);int RT=root; // cerr<<*pos<<' '<<RT<<'\n';for (int i=0;i<(int)block.size();i++) {int v=block[i];SGT::dfs(rt[v]),SGT::dfs(prt[v]);fa[v]=idx[v]=rt[v]=prt[v]=0;son[v].clear(),sub[v].clear();}fa[RT]=f,idx[RT]=id,*pos=RT;build();block.clear();pos=NULL;} return 0; }

    總結(jié)

    以上是生活随笔為你收集整理的【WC2014】紫荆花之恋【替罪羊思想】【动态点分树】【替罪羊树】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。