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
",ans[i]);
164     return 0;
165 }
原文地址:https://www.cnblogs.com/guapisolo/p/10603729.html