LOJ2116 [HNOI2015] 开店 【点分治】

题目分析:

  观察题目发现度数不小于三,考虑从边分治入手,用点分治代替。将树划分成重心链接的结构,称为点分树。令当前询问的点为$ u $。那么我们考虑点分树的根到$ u $的一条路径。考虑根结点,排除掉与$ u $有关的点所在的子树,剩下的点到$ u $的路径长度等价于它们到根的路径加上根到$ u $的路径。所以我们要做的是消去$ u $所在子树的影响,然后递归问题。这个做法在点分治意义下是常用做法,前缀和维护即可。由于每个点都在点分路径上的前缀和上出现了一次,而点分树高为$ O(\log n) $,所以空间为$ O(n*\log n) $。时间是$ O(n*\log^2n) $

 

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int maxn = 150005;
  5 
  6 int n,Q,A;
  7 
  8 int x[maxn];
  9 
 10 vector <pair<int,int> > g[maxn];
 11 int euler[maxn<<1],nE,app[maxn][2];
 12 int RMQ[maxn<<1][19],f[maxn],dep[maxn],climb[maxn];
 13 
 14 template<typename T>
 15 void in(T &x){
 16     x = 0; char ch = getchar();
 17     while(ch > '9' || ch < '0') ch = getchar();
 18     while(ch >= '0' && ch <= '9') x = x*10+ch-'0',ch=getchar();
 19 }
 20 
 21 void dfs(int now,int last,int dp,int cl){
 22     dep[now] = dp; f[now] = last; climb[now] = cl;
 23     euler[++nE] = now; app[now][0] = app[now][1] = nE;
 24     for(int i=0;i<g[now].size();i++){
 25     int pp = g[now][i].first,len = g[now][i].second;
 26     if(pp == last) continue;
 27     dfs(pp,now,dp+len,cl+1);
 28     euler[++nE] = now; app[now][1] = nE;
 29     }
 30 }
 31 
 32 void BuildRMQ(){
 33     for(int i=1;i<=nE;i++) RMQ[i][0] = euler[i];
 34     for(int k=1;(1<<k)<=nE;k++){
 35     for(int i=1;i<=nE;i++){
 36         if(i+(1<<k-1) > nE) {RMQ[i][k] = RMQ[i][k-1];continue;}
 37         if(climb[RMQ[i][k-1]] < climb[RMQ[i+(1<<k-1)][k-1]]){
 38         RMQ[i][k] = RMQ[i][k-1];
 39         }else RMQ[i][k] = RMQ[i+(1<<k-1)][k-1];
 40     }
 41     }
 42 }
 43 
 44 int QueryLCA(int u,int v){
 45     int fst = min(app[u][0],app[v][0]),sec = max(app[u][1],app[v][1]);
 46     int len = sec-fst+1,k = 0;
 47     while((1<<k+1) <= len) k++;
 48     if(climb[RMQ[fst][k]] < climb[RMQ[sec-(1<<k)+1][k]]) return RMQ[fst][k];
 49     else return RMQ[sec-(1<<k)+1][k];
 50 }
 51 
 52 int dist(int u,int v){ return dep[u]+dep[v]-2*dep[QueryLCA(u,v)]; }
 53 
 54 class Pdivide{
 55 private:
 56     int sz[maxn],arr[maxn],seg[maxn],fa[maxn];
 57     vector <pair<int,int> > v[maxn],v2[maxn];
 58     vector <long long> sum[maxn],sum2[maxn];
 59     stack <int> sta;
 60     void GetSize(int now,int last){
 61     sz[now] = 0;seg[now] = 0;
 62     for(int i=0;i<g[now].size();i++){
 63         int pp = g[now][i].first;
 64         if(arr[pp] || pp == last) continue;
 65         GetSize(pp,now);
 66         sz[now] += sz[pp];
 67         seg[now] = max(seg[now],sz[pp]);
 68     }
 69     sz[now]++;
 70     }
 71     int GetG(int now,int last,int tot){
 72     int res = now; seg[now] = max(seg[now],tot-sz[now]-1);
 73     for(int i=0;i<g[now].size();i++){
 74         int pp = g[now][i].first;
 75         if(arr[pp] || pp == last) continue;
 76         int p = GetG(pp,now,tot);
 77         if(seg[p] < seg[res]) res = p;
 78     }
 79     return res;
 80     }
 81     void LenQuery(int now,int last,int dst,int root,int oldroot){
 82     v[root].push_back(make_pair(x[now],dst));
 83     if(oldroot != 0) v2[root].push_back(make_pair(x[now],dist(now,oldroot)));
 84     for(int i=0;i<g[now].size();i++){
 85         int pp = g[now][i].first, len = g[now][i].second;
 86         if(arr[pp] || pp == last) continue;
 87         LenQuery(pp,now,dst+len,root,oldroot);
 88     }
 89     }
 90     void divide(int now,int last,int ht){
 91     GetSize(now,0);
 92     int p = GetG(now,0,sz[now]);
 93 
 94     LenQuery(p,0,0,p,last);    sort(v[p].begin(),v[p].end()); sum[p].push_back(0);
 95     sort(v2[p].begin(),v2[p].end()); sum2[p].push_back(0);
 96     for(int i=0;i<v[p].size();i++) sum[p].push_back(sum[p][i]+1ll*v[p][i].second);
 97     for(int i=0;i<v2[p].size();i++) sum2[p].push_back(sum2[p][i]+1ll*v2[p][i].second);
 98 
 99     fa[p] = last;arr[p] = ht;
100     for(int i=0;i<g[p].size();i++){        
101         int nxt = g[p][i].first;
102         if(arr[nxt]) continue;
103         divide(nxt,p,ht+1);
104     }
105     }
106 
107 public:
108     void BuildTree(){divide(1,0,1);}
109     void printans(int now,int l,int r,long long &lastans){
110     int p = now;
111     while(p != 0) sta.push(p),p = fa[p];
112     long long ans = 0;
113     while(!sta.empty()){
114         int tp = sta.top();sta.pop();
115         int pp = lower_bound(v[tp].begin(),v[tp].end(),make_pair(l,0))-v[tp].begin();
116         if(pp == v[tp].size()||v[tp][pp].first > r) break;
117         int ed = upper_bound(v[tp].begin(),v[tp].end(),make_pair(r,(int)1E9))-v[tp].begin()-1;
118         int len = ed-pp+1;
119         ans += sum[tp][ed+1] - sum[tp][pp] + 1ll*len*dist(tp,now);
120         if(fa[tp]!=0)
121         ans -= (sum2[tp][ed+1] - sum2[tp][pp] + 1ll*len*dist(fa[tp],now));
122     }
123     while(!sta.empty())sta.pop();
124     printf("%lld\n",ans);lastans = ans;
125     }
126 }T1;
127 
128 void init(){
129     dfs(1,0,0,1);
130     BuildRMQ();
131     T1.BuildTree();
132 }
133 
134 void work(){
135     long long lastans = 0;
136     for(int i=1;i<=Q;i++){
137     int a,u,v; in(a),in(u),in(v);
138     u = (1ll*u+lastans)%A;
139     v = (1ll*v+lastans)%A;
140     if(u > v) swap(u,v);
141      T1.printans(a,u,v,lastans);
142     }
143 }
144 
145 int main(){
146     in(n),in(Q),in(A);
147     for(int i=1;i<=n;i++) in(x[i]);
148     for(int i=1;i<n;i++){
149     int u,v,w; in(u),in(v),in(w);
150     g[u].push_back(make_pair(v,w));
151     g[v].push_back(make_pair(u,w));
152     }
153     init();
154     work();
155     return 0;
156 }

 

posted @ 2018-05-26 11:31  menhera  阅读(283)  评论(0编辑  收藏  举报