1. 程式人生 > >bzoj4285 使者 樹狀陣列套線段樹

bzoj4285 使者 樹狀陣列套線段樹

Description


公元 8192 年,人類進入星際大航海時代。在不懈的努力之下,人類佔領了
宇宙中的 n 個行星,並在這些行星之間修建了 n - 1 條星際航道,使得任意兩個
行星之間可以通過唯一的一條路徑互相到達。
同時,在宇宙中還有一些空間跳躍點,有些跳躍點已經被發現,還有一些是
未知的,每個跳躍點連線了兩個行星,使得這兩個行星中的任意一個都可以通過
這個跳躍點到達另外一個行星。這些跳躍點因為充斥著巨大的能量,所以它們很
容易崩潰。
宇宙中還有一些意圖毀滅人類的外星人,他們派出了一些使者潛伏在行星
上。現在這些使者想要離開他們各自藏身的行星u,到其他行星 v 去搜集情報。
由於這些使者十分小心, 他們不會經過任意一條屬於這兩個行星的路徑上的星際
航道(即不會走在 u 到 v 路徑上的星際航道) 。這樣他們就只能藉助一些跳躍點
來到達目的地,但是這些外星人的身體十分脆弱,所以他們只能通過最多一個跳
躍點。
現在告訴你若干個按照時間順序給出的事件,每個事件可能是一個跳躍點又
被發現了,也可能是一個跳躍點崩潰了,還有可能是一個外星使者想離開行星u
到行星v去。
請問每個外星使者有多少條不同的路徑可以選擇?

對於100%的資料,n ≤ 105,m ≤ 5 × 104,q ≤ 5 × 104 資料保證x不等於y

Solution


純粹為了練碼速,結果到最後調傻了。。
對於一條邊(x,y),若x和y非祖先的關係,那麼只有x子樹內的點走到y子樹內的點才會產生1的貢獻
若x為y的祖先,z為x到y鏈上非y的最淺點,那麼只有x子樹內的點走到z子樹補集內的點才會產生1的貢獻
乍一看這是一個區間矩形修改+單點查詢的樹套樹題目,實際上如果我們把非樹邊(x,y)看成座標為(dfn[x],dfn[y])的二維平面上的點,那麼查詢(a,b)等價於按照上面的方法查詢矩形和,修改就變成了單點修改了

然後樹狀陣列套線段樹就可以了,空間夠隨便開

打錯了一點地方調了很久GG,老年選手.jpg

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define lowbit(x) (x&(-x))

const int N=100005;

struct treeNode {int l,
r,sum;} t[N*401]; struct edge {int y,next;} e[N*2]; int pos[N],dep[N],fa[N],bl[N],size[N],n; int root[N*2],ls[N],edCnt,tot; int read() { int x=0,v=1; char ch=getchar(); for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar()); for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar()); return x*v; } void add_edge(int x,int y) { e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt; e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt; } void modify(int &now,int tl,int tr,int x,int v) { if (!now) now=++tot; t[now].sum+=v; if (tl==tr) return ; int mid((tl+tr)>>1); if (x<=mid) modify(t[now].l,tl,mid,x,v); else modify(t[now].r,mid+1,tr,x,v); } int query(int now,int tl,int tr,int l,int r) { if (r<l||!now) return 0; if (tl>=l&&tr<=r) return t[now].sum; int mid((tl+tr)>>1); int qx=query(t[now].l,tl,mid,l,std:: min(r,mid)); int qy=query(t[now].r,mid+1,tr,std:: max(mid+1,l),r); return qx+qy; } void change(int x,int p,int v) { for (;x<=pos[0];x+=lowbit(x)) modify(root[x],1,pos[0],p,v); } int get(int x,int l,int r) { int res=0; for (;x;x-=lowbit(x)) res+=query(root[x],1,pos[0],l,r); return res; } int ask(int x,int y,int l,int r) { if (x>y) return 0; return get(y,l,r)-get(x-1,l,r); } void dfs1(int now) { size[now]=1; for (int i=ls[now];i;i=e[i].next) { if (e[i].y==fa[now]) continue; fa[e[i].y]=now; dep[e[i].y]=dep[now]+1; dfs1(e[i].y); size[now]+=size[e[i].y]; } } void dfs2(int now,int up) { bl[now]=up; pos[now]=++pos[0]; int mx=0; for (int i=ls[now];i;i=e[i].next) { if (e[i].y!=fa[now]&&size[e[i].y]>size[mx]) mx=e[i].y; } if (!mx) return ; dfs2(mx,up); for (int i=ls[now];i;i=e[i].next) { if (e[i].y!=fa[now]&&e[i].y!=mx) dfs2(e[i].y,e[i].y); } } int get_lca(int x,int y) { for (;bl[x]!=bl[y];) { if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y); x=fa[bl[x]]; } return dep[x]<dep[y]?x:y; } int get_up(int x,int y) { if (fa[x]==y) return x; for (;bl[x]!=bl[y];) { if (fa[bl[x]]==y) return bl[x]; x=fa[bl[x]]; } for (int i=ls[y];i;i=e[i].next) { if (e[i].y!=fa[y]&&bl[e[i].y]==bl[y]) return e[i].y; } } int main(void) { n=read(); rep(i,2,n) add_edge(read(),read()); dfs1(1); dfs2(1,1); int m=read(); rep(i,1,m) { int x=read(),y=read(); if (pos[x]>pos[y]) std:: swap(x,y); change(pos[x],pos[y],1); } for (int T=read();T--;) { int opt=read(),x=read(),y=read(); if (pos[x]>pos[y]) std:: swap(x,y); if (opt==1) change(pos[x],pos[y],1); else if (opt==2) change(pos[x],pos[y],-1); else { int lca=get_lca(x,y),ans=0; if (lca==x) { int up=get_up(y,x); ans=ask(pos[y],pos[y]+size[y]-1,pos[up]+size[up],pos[0]); ans+=ask(1,pos[up]-1,pos[y],pos[y]+size[y]-1); } else ans=ask(pos[x],pos[x]+size[x]-1,pos[y],pos[y]+size[y]-1); printf("%d\n", ans); } } return 0; }