日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[XSY3112] 接水果(树上包含路径,整体二分,扫描线)

發布時間:2023/12/3 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [XSY3112] 接水果(树上包含路径,整体二分,扫描线) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門

給出一棵nnn個點的樹。接下來給出PPP條樹上路徑ai→bia_i\to b_iai?bi?,及其權值cic_ici?。最后有QQQ個詢問,每個詢問給出一條樹上路徑ui→viu_i\to v_iui?vi?,問在包含ui→viu_i\to v_iui?vi?的所有樹上路徑中(包含指ui→viu_i\to v_iui?vi?ai→bia_i\to b_iai?bi?的子路徑),權值第kkk小的路徑權值是多少?

不妨設dep[u]<dep[v]dep[u]<dep[v]dep[u]<dep[v]
lca(u,v)=ulca(u,v)=ulca(u,v)=u,記pppuuu在向vvv方向的兒子,
那么包含u→vu\to vuv的路徑a→ba\to bab一定滿足:a∈?subtreep,b∈subtreeva\not\in subtree_p,b\in subtree_va?subtreep?,bsubtreev?
lca(u,v)=?ulca(u,v)\not=ulca(u,v)?=u
那么包含u→vu\to vuv的路徑a→ba\to bab一定滿足:a∈subtreeu,b∈subtreeva\in subtree_u,b\in subtree_vasubtreeu?,bsubtreev?

也就是說,對于包含u→vu\to vuv的路徑a→ba\to babdfn[a],dfn[b]dfn[a],dfn[b]dfn[a],dfn[b]的取值范圍是 一段或兩端區間。
因此所有符合條件的路徑a→ba\to bab可以用二維平面上的 一個或兩個矩形 表示出來。

原題要求的就是所有包含詢問點矩形中權值第kkk小的。

考慮整體二分,統計一個點在多少個 權值在[l,r][l,r][l,r]內的矩形 中出現過。用掃描線解決。

#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=80010; struct Edge{int v,nxt;}edge[N]; int n,m,q,cnt,head[N]; int fa[N][20],dep[N],ind,dfn[N],lst[N]; int tot,ans[N],sum[N]; struct Rectangle{int xd,xu,yd,yu,v;}rect[N]; bool operator < (Rectangle a,Rectangle b){return a.v<b.v;} struct Point{int x,y,k,id;}pt[N],tmp1[N],tmp2[N]; struct Line{int x,yd,yu,v,id;}line[N]; bool operator < (Line a,Line b){return a.x==b.x?a.id<b.id:a.x<b.x;} struct Bit{int val[N];void modify(int l,int r,int v){for(int i=l;i<=n;i+=(i&(-i))) val[i]+=v;for(int i=r+1;i<=n;i+=(i&(-i))) val[i]-=v;}int query(int x){int res=0;for(;x;x-=(x&(-x))) res+=val[x];return res;} }T; void add(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt; } void dfs(int u){dfn[u]=++ind;for(int i=0;fa[u][i];i++) fa[u][i+1]=fa[fa[u][i]][i];for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa[u][0]) continue;fa[v][0]=u;dep[v]=dep[u]+1;dfs(v);}lst[u]=ind; } int jump(int u,int dis){for(int i=18;dis;i--){if(dis>=(1<<i)){dis-=(1<<i);u=fa[u][i];}}return u; } int LCA(int u,int v){if(dep[u]<dep[v]) swap(u,v);u=jump(u,dep[u]-dep[v]);if(u==v) return u;for(int i=18;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];return fa[u][0]; } void solve(int l,int r,int st,int ed){if(st>ed) return;if(l==r){for(int i=st;i<=ed;i++) ans[pt[i].id]=rect[l].v;return;}int mid=(l+r)>>1,siz=0;for(int i=l;i<=mid;i++){line[++siz]=(Line){rect[i].xd,rect[i].yd,rect[i].yu,1,0};line[++siz]=(Line){rect[i].xu,rect[i].yd,rect[i].yu,-1,n+1};}for(int i=st;i<=ed;i++) line[++siz]=(Line){pt[i].x,pt[i].y,0,0,i};sort(line+1,line+siz+1);for(int i=1;i<=siz;i++){if(st<=line[i].id&&line[i].id<=ed) sum[line[i].id]=T.query(line[i].yd);else T.modify(line[i].yd,line[i].yu,line[i].v);}int a=0,b=0;for(int i=st;i<=ed;i++){if(sum[i]>=pt[i].k) tmp1[++a]=pt[i];else tmp2[++b]=(Point){pt[i].x,pt[i].y,pt[i].k-sum[i],pt[i].id};}for(int i=st;i<=st+a-1;i++) pt[i]=tmp1[i-st+1];for(int i=st+a;i<=ed;i++) pt[i]=tmp2[i-st-a+1];solve(l,mid,st,st+a-1);solve(mid+1,r,st+a,ed); } int main(){scanf("%d%d%d",&n,&m,&q);for(int i=1;i<n;i++){int a,b;scanf("%d%d",&a,&b);add(a,b);add(b,a);}dfs(1);for(int i=1;i<=m;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);int u=LCA(a,b);if(dfn[a]>dfn[b]) swap(a,b);if(u!=a) rect[++tot]=(Rectangle){dfn[a],lst[a],dfn[b],lst[b],c};else{int w=jump(b,dep[b]-dep[a]-1);rect[++tot]=(Rectangle){1,dfn[w]-1,dfn[b],lst[b],c};if(lst[w]<n) rect[++tot]=(Rectangle){dfn[b],lst[b],lst[w]+1,n,c};}}sort(rect+1,rect+tot+1);for(int i=1;i<=q;i++){int a,b,k;scanf("%d%d%d",&a,&b,&k);if(dfn[a]>dfn[b]) swap(a,b);pt[i]=(Point){dfn[a],dfn[b],k,i};}solve(1,tot,1,q);for(int i=1;i<=q;i++) printf("%d\n",ans[i]);return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的[XSY3112] 接水果(树上包含路径,整体二分,扫描线)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。