BZOJ 4285 使者 (CDQ分治+dfs序)

題目傳送門

題目大意:給你一棵樹,有三種操作,在兩個點之間連一個傳送門,拆毀一個已有的傳送門,詢問兩個點之間的合法路徑數量。一條合法路徑滿足 1.經過且僅經過一個傳送門 2.不經過起點終點簡單路徑上的任何一條邊

這模型轉化好神啊

首先把樹拍成$dfs$序

問題是在樹上,我們把$x,y$這條鏈拎出來攤平,那麼鏈上每個點都掛了一些子樹。

容易發現合法路徑數=連接以$x,y$爲根的子樹的傳送門數量

而無根樹並沒有“子樹”這一概念,所以先隨便挑一個根跑出來dfs序。

發現“子樹”的$dfs$序一定是一個或兩個連續的區間,我們分$x,y$是否爲$lca$討論一下就可以了

然後把問題放到二維座標系上。

問題轉化成,動態在一個二維平面內加入/刪除一個點,以及查詢矩形內點的數量

由於存在修改操作,需要再加上一維。那麼整個問題變成了一個三維偏序問題。用$CDQ$分治+樹狀數組即可

 

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 100005
  6 #define M1 500005
  7 #define ll long long 
  8 #define uint unsigned int 
  9 using namespace std;
 10  
 11 template <typename _T> void read(_T &ret)
 12 {
 13     ret=0; _T fh=1; char c=getchar();
 14     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
 15     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
 16     ret=ret*fh;
 17 }
 18  
 19 struct Edge{
 20 int to[N1*2],nxt[N1*2],head[N1],cte;
 21 void ae(int u,int v)
 22 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
 23 }e;
 24  
 25 int n;
 26  
 27 namespace Tree{
 28 int dep[N1],fa[N1],ff[N1][19],st[N1],ed[N1],ord[N1],cur;
 29 void dfs1(int x)
 30 {
 31     int j,v; ff[x][0]=x; st[x]=++cur; ord[cur]=x;//sz[x]=1; 
 32     for(j=e.head[x];j;j=e.nxt[j])
 33     {
 34         v=e.to[j]; if(v==fa[x]) continue;
 35         fa[v]=x; ff[v][1]=x; dep[v]=dep[x]+1;
 36         dfs1(v);
 37     }
 38     ed[x]=cur;
 39 }
 40 void init()
 41 { 
 42     dep[1]=1; dfs1(1); 
 43     int i,j;
 44     for(j=2;j<=18;j++)
 45     for(i=1;i<=n;i++)
 46         ff[i][j]=ff[ ff[i][j-1] ][j-1];
 47 }
 48 int LCA(int x,int y)
 49 {
 50     int i,ans=0;
 51     if(dep[x]<dep[y]) swap(x,y);
 52     for(i=18;i>=0;i--)
 53         if(dep[ff[x][i]]>=dep[y]) x=ff[x][i];
 54     if(x==y) return x;
 55     for(i=18;i>=0;i--)
 56         if(ff[x][i]==ff[y][i]) ans=ff[x][i];
 57         else x=ff[x][i], y=ff[y][i];
 58     return ans;
 59 }
 60 int LCB(int x,int D)
 61 {
 62     int i;
 63     for(i=18;i>=0;i--) 
 64         if(dep[ff[x][i]]>=D) x=ff[x][i];
 65     return x;
 66 }
 67 };
 68  
 69 struct BIT{
 70 int sum[N1];
 71 void upd(int x,int w)
 72 {
 73     if(!x) return; int i;
 74     for(i=x;i<=n;i+=(i&(-i)))
 75         sum[i]+=w;
 76 }
 77 int query(int x)
 78 {
 79     int ans=0,i;
 80     for(i=x;i>0;i-=(i&(-i)))
 81         ans+=sum[i];
 82     return ans;
 83 }
 84 void clr(int x)
 85 {
 86     int i;
 87     for(i=x;i<=n;i+=(i&(-i)))
 88         sum[i]=0;
 89 }
 90 }bit;
 91  
 92 struct OP{  int x,y,t,type,f; }op[M1],tmp[M1];
 93 int cmp2(OP &s1,OP &s2)
 94 { 
 95     if(s1.x!=s2.x) return s1.x<s2.x; 
 96     if(s1.y!=s2.y) return s1.y<s2.y;
 97     return s1.type<s2.type;
 98 }
 99 int ans[N1],que[M1],isquery[N1],tl;
100  
101 void CDQ(int L,int R)
102 {
103     if(L==R) return; 
104     int M=(L+R)>>1,i,j,cnt=0;
105     CDQ(L,M); CDQ(M+1,R);
106     for(i=L,j=M+1;i<=M&&j<=R;)
107     {
108         if(cmp2(op[i],op[j])){
109             if(!op[i].type) bit.upd(op[i].y,op[i].f), que[++tl]=op[i].y;
110             tmp[++cnt]=op[i]; i++;
111         }else{
112             if(op[j].type) ans[op[j].t]+=op[j].f*bit.query(op[j].y);
113             tmp[++cnt]=op[j]; j++;
114         }
115     }
116     while(i<=M){ tmp[++cnt]=op[i]; i++; }
117     while(j<=R){ tmp[++cnt]=op[j]; if(op[j].type) ans[op[j].t]+=op[j].f*bit.query(op[j].y); j++; }
118     for(i=L;i<=R;i++) op[i]=tmp[i-L+1];
119     while(tl){ bit.clr(que[tl]); tl--; }
120 }
121  
122 int m,Q1,Q2;
123 using Tree::st; using Tree::ed; using Tree::dep; using Tree::LCA; using Tree::LCB;
124  
125 int main()
126 {
127     scanf("%d",&n); 
128     int i,j,x,y,z,F,q,fl;
129     for(i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
130     Tree::init();
131     read(Q1);
132     for(q=1;q<=Q1;q++) 
133     {
134         read(x); read(y); 
135         op[++m]=(OP){st[x],st[y],0,0,1}; op[++m]=(OP){st[y],st[x],0,0,1};
136     }
137     read(Q2);
138     for(q=1;q<=Q2;q++) {
139      
140     read(fl); read(x); read(y);
141     if(fl==1){
142         op[++m]=(OP){st[x],st[y],q,0,1}; op[++m]=(OP){st[y],st[x],q,0,1};
143     }else if(fl==2){
144         op[++m]=(OP){st[x],st[y],q,0,-1}; op[++m]=(OP){st[y],st[x],q,0,-1};
145     }else if(fl==3){
146         F=LCA(x,y); isquery[q]=1;
147         if(x==F||y==F){
148             if(x==F) swap(x,y); z=LCB(x,dep[F]+1); 
149             op[++m]=(OP){ed[x],st[z]-1,q,1,1};    //op[++m]=(OP){ed[x],0,q,1,-1};
150             op[++m]=(OP){st[x]-1,st[z]-1,q,1,-1}; //op[++m]=(OP){st[x]-1,0,q,1,1};
151             op[++m]=(OP){ed[x],n,q,1,1};    op[++m]=(OP){ed[x],ed[z],q,1,-1};
152             op[++m]=(OP){st[x]-1,n,q,1,-1}; op[++m]=(OP){st[x]-1,ed[z],q,1,1};
153         }else{
154             op[++m]=(OP){ed[x],ed[y],q,1,1};    op[++m]=(OP){ed[x],st[y]-1,q,1,-1};
155             op[++m]=(OP){st[x]-1,ed[y],q,1,-1}; op[++m]=(OP){st[x]-1,st[y]-1,q,1,1};   
156         }
157     }
158      
159     }
160      
161     CDQ(1,m);
162     for(i=1;i<=Q2;i++) if(isquery[i])
163         printf("%d\n",ans[i]);
164     return 0;
165 }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章